From 90a4b66366cf94e7aa8317fb37951bc7419a08c2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 27 Sep 2016 16:37:18 +0300 Subject: [PATCH 1/6] New media type Game added. Display of Game partially supported. --- Telegram/SourceFiles/apiwrap.cpp | 53 +- Telegram/SourceFiles/app.cpp | 158 ++- Telegram/SourceFiles/app.h | 38 +- Telegram/SourceFiles/application.cpp | 6 +- Telegram/SourceFiles/boxes/connectionbox.cpp | 3 +- Telegram/SourceFiles/history.cpp | 665 +++++----- Telegram/SourceFiles/history.h | 141 ++- .../history/history_location_manager.cpp | 251 ++++ .../history/history_location_manager.h | 120 ++ Telegram/SourceFiles/historywidget.cpp | 11 +- .../inline_bot_layout_internal.cpp | 1 + .../inline_bots/inline_bot_send_data.h | 4 +- Telegram/SourceFiles/localstorage.cpp | 8 +- Telegram/SourceFiles/mainwidget.cpp | 144 ++- Telegram/SourceFiles/mainwidget.h | 10 +- Telegram/SourceFiles/mtproto/scheme.tl | 31 +- Telegram/SourceFiles/mtproto/scheme_auto.cpp | 198 ++- Telegram/SourceFiles/mtproto/scheme_auto.h | 1065 ++++++++++++++--- .../SourceFiles/overview/overview_layout.cpp | 6 +- Telegram/SourceFiles/pspecific_win.cpp | 1 + Telegram/SourceFiles/structs.cpp | 42 +- Telegram/SourceFiles/structs.h | 95 +- Telegram/gyp/Telegram.gyp | 2 + 23 files changed, 2241 insertions(+), 812 deletions(-) create mode 100644 Telegram/SourceFiles/history/history_location_manager.cpp create mode 100644 Telegram/SourceFiles/history/history_location_manager.h diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 65cf0717e9..05c4cdef80 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1046,26 +1046,25 @@ void ApiWrap::clearWebPageRequests() { void ApiWrap::resolveWebPages() { MessageIds ids; // temp_req_id = -1 - typedef QPair IndexAndMessageIds; - typedef QMap MessageIdsByChannel; + using IndexAndMessageIds = QPair; + using MessageIdsByChannel = QMap; MessageIdsByChannel idsByChannel; // temp_req_id = -index - 2 - const WebPageItems &items(App::webPageItems()); + auto &items = App::webPageItems(); ids.reserve(_webPagesPending.size()); int32 t = unixtime(), m = INT_MAX; - for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { + for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { if (i.value() > 0) continue; if (i.key()->pendingTill <= t) { - WebPageItems::const_iterator j = items.constFind(i.key()); + auto j = items.constFind(i.key()); if (j != items.cend() && !j.value().isEmpty()) { - for (HistoryItemsMap::const_iterator it = j.value().cbegin(); it != j.value().cend(); ++it) { - HistoryItem *item = j.value().begin().key(); + for_const (auto item, j.value()) { if (item->id > 0) { if (item->channelId() == NoChannel) { ids.push_back(MTP_int(item->id)); i.value() = -1; } else { - ChannelData *channel = item->history()->peer->asChannel(); + auto channel = item->history()->peer->asChannel(); MessageIdsByChannel::iterator channelMap = idsByChannel.find(channel); if (channelMap == idsByChannel.cend()) { channelMap = idsByChannel.insert(channel, IndexAndMessageIds(idsByChannel.size(), MessageIds(1, MTP_int(item->id)))); @@ -1083,20 +1082,20 @@ void ApiWrap::resolveWebPages() { } } - mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector(ids)), rpcDone(&ApiWrap::gotWebPages, (ChannelData*)0), RPCFailHandlerPtr(), 0, 5); - typedef QVector RequestIds; + mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector(ids)), rpcDone(&ApiWrap::gotWebPages, (ChannelData*)nullptr), RPCFailHandlerPtr(), 0, 5); + using RequestIds = QVector; RequestIds reqsByIndex(idsByChannel.size(), 0); - for (MessageIdsByChannel::const_iterator i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) { + for (auto i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) { reqsByIndex[i.value().first] = MTP::send(MTPchannels_GetMessages(i.key()->inputChannel, MTP_vector(i.value().second)), rpcDone(&ApiWrap::gotWebPages, i.key()), RPCFailHandlerPtr(), 0, 5); } if (req || !reqsByIndex.isEmpty()) { - for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { - if (i.value() > 0) continue; - if (i.value() < 0) { - if (i.value() == -1) { - i.value() = req; + for (auto &requestId : _webPagesPending) { + if (requestId > 0) continue; + if (requestId < 0) { + if (requestId == -1) { + requestId = req; } else { - i.value() = reqsByIndex[-i.value() - 2]; + requestId = reqsByIndex[-requestId - 2]; } } } @@ -1115,21 +1114,21 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs const QVector *v = 0; switch (msgs.type()) { case mtpc_messages_messages: { - const auto &d(msgs.c_messages_messages()); + auto &d = msgs.c_messages_messages(); App::feedUsers(d.vusers); App::feedChats(d.vchats); v = &d.vmessages.c_vector().v; } break; case mtpc_messages_messagesSlice: { - const auto &d(msgs.c_messages_messagesSlice()); + auto &d = msgs.c_messages_messagesSlice(); App::feedUsers(d.vusers); App::feedChats(d.vchats); v = &d.vmessages.c_vector().v; } break; case mtpc_messages_channelMessages: { - auto &d(msgs.c_messages_channelMessages()); + auto &d = msgs.c_messages_channelMessages(); if (channel) { channel->ptsReceived(d.vpts.v); } else { @@ -1152,21 +1151,21 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs } } - for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - if (HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting)) { + for_const (auto msgId, msgsIds) { + if (auto item = App::histories().addNewMessage(v->at(msgId), NewMessageExisting)) { item->setPendingInitDimensions(); } } - const WebPageItems &items(App::webPageItems()); - for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend();) { + auto &items = App::webPageItems(); + for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) { if (i.value() == req) { if (i.key()->pendingTill > 0) { i.key()->pendingTill = -1; - WebPageItems::const_iterator j = items.constFind(i.key()); + auto j = items.constFind(i.key()); if (j != items.cend()) { - for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) { - k.key()->setPendingInitDimensions(); + for_const (auto item, j.value()) { + item->setPendingInitDimensions(); } } } diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index e8d7636474..fcdfe3dcf6 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "data/data_abstract_structure.h" #include "history/history_service_layout.h" +#include "history/history_location_manager.h" #include "media/media_audio.h" #include "inline_bots/inline_bot_layout_item.h" #include "application.h" @@ -44,47 +45,51 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace { App::LaunchState _launchState = App::Launched; - UserData *self = 0; + UserData *self = nullptr; - typedef QHash PeersData; + using PeersData = QHash; PeersData peersData; - typedef QMap MutedPeers; + using MutedPeers = QMap; MutedPeers mutedPeers; - typedef QMap UpdatedPeers; + using UpdatedPeers = QMap; UpdatedPeers updatedPeers; PhotosData photosData; DocumentsData documentsData; - typedef QHash LocationsData; + using LocationsData = QHash; LocationsData locationsData; - typedef QHash WebPagesData; + using WebPagesData = QHash; WebPagesData webPagesData; + using GamesData = QHash; + GamesData gamesData; + PhotoItems photoItems; DocumentItems documentItems; WebPageItems webPageItems; + GameItems gameItems; SharedContactItems sharedContactItems; GifItems gifItems; - typedef OrderedSet DependentItemsSet; - typedef QMap DependentItems; + using DependentItemsSet = OrderedSet; + using DependentItems = QMap; DependentItems dependentItems; Histories histories; - typedef QHash MsgsData; + using MsgsData = QHash; MsgsData msgsData; - typedef QMap ChannelMsgsData; + using ChannelMsgsData = QMap; ChannelMsgsData channelMsgsData; - typedef QMap RandomData; + using RandomData = QMap; RandomData randomData; - typedef QMap > SentData; + using SentData = QMap>; SentData sentData; HistoryItem *hoveredItem = nullptr, @@ -94,7 +99,7 @@ namespace { *contextItem = nullptr, *mousedItem = nullptr; - QPixmap *emoji = 0, *emojiLarge = 0; + QPixmap *emoji = nullptr, *emojiLarge = nullptr; style::font monofont; struct CornersPixmaps { @@ -104,19 +109,19 @@ namespace { QPixmap *p[4]; }; CornersPixmaps corners[RoundCornersCount]; - typedef QMap CornersMap; + using CornersMap = QMap; CornersMap cornersMap; - QImage *cornersMaskLarge[4] = { 0 }, *cornersMaskSmall[4] = { 0 }; + QImage *cornersMaskLarge[4] = { nullptr }, *cornersMaskSmall[4] = { nullptr }; - typedef QMap EmojiMap; + using EmojiMap = QMap; EmojiMap mainEmojiMap; QMap otherEmojiMap; int32 serviceImageCacheSize = 0; - typedef QLinkedList LastPhotosList; + using LastPhotosList = QLinkedList; LastPhotosList lastPhotos; - typedef QHash LastPhotosMap; + using LastPhotosMap = QHash; LastPhotosMap lastPhotosMap; style::color _msgServiceBg; @@ -1472,7 +1477,7 @@ namespace { DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) { switch (document.type()) { case mtpc_document: { - const auto &d(document.c_document()); + auto &d = document.c_document(); return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation()); } break; case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); @@ -1514,7 +1519,11 @@ namespace { } break; case mtpc_webPagePending: return App::feedWebPage(webpage.c_webPagePending()); } - return 0; + return nullptr; + } + + GameData *feedGame(const MTPDgame &game, GameData *convert) { + return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), qs(game.vurl), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr); } UserData *curUser() { @@ -1754,8 +1763,8 @@ namespace { auto &items = App::documentItems(); auto i = items.constFind(result); if (i != items.cend()) { - for (auto j = i->cbegin(), e = i->cend(); j != e; ++j) { - j.key()->setPendingInitDimensions(); + for_const (auto item, i.value()) { + item->setPendingInitDimensions(); } } } @@ -1763,7 +1772,7 @@ namespace { } WebPageData *webPage(const WebPageId &webPage) { - WebPagesData::const_iterator i = webPagesData.constFind(webPage); + auto i = webPagesData.constFind(webPage); if (i == webPagesData.cend()) { i = webPagesData.insert(webPage, new WebPageData(webPage)); } @@ -1773,7 +1782,7 @@ namespace { WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document, int32 duration, const QString &author, int32 pendingTill) { if (convert) { if (convert->id != webPage) { - WebPagesData::iterator i = webPagesData.find(convert->id); + auto i = webPagesData.find(convert->id); if (i != webPagesData.cend() && i.value() == convert) { webPagesData.erase(i); } @@ -1795,7 +1804,7 @@ namespace { if (App::main()) App::main()->webPageUpdated(convert); } } - WebPagesData::const_iterator i = webPagesData.constFind(webPage); + auto i = webPagesData.constFind(webPage); WebPageData *result; if (i == webPagesData.cend()) { if (convert) { @@ -1830,8 +1839,63 @@ namespace { return result; } + GameData *game(const GameId &game) { + auto i = gamesData.constFind(game); + if (i == gamesData.cend()) { + i = gamesData.insert(game, new GameData(game)); + } + return i.value(); + } + + GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) { + if (convert) { + if (convert->id != game) { + auto i = gamesData.find(convert->id); + if (i != gamesData.cend() && i.value() == convert) { + gamesData.erase(i); + } + convert->id = game; + } + if (convert->url.isEmpty() && !url.isEmpty()) { + convert->accessHash = accessHash; + convert->shortName = shortName; + convert->title = title; + convert->description = description; + convert->url = url; + convert->photo = photo; + convert->document = document; + if (App::main()) App::main()->gameUpdated(convert); + } + } + auto i = gamesData.constFind(game); + GameData *result; + if (i == gamesData.cend()) { + if (convert) { + result = convert; + } else { + result = new GameData(game, accessHash, shortName, title, description, url, photo, document); + } + gamesData.insert(game, result); + } else { + result = i.value(); + if (result != convert) { + if (result->url.isEmpty() && !url.isEmpty()) { + result->accessHash = accessHash; + result->shortName = shortName; + result->title = title; + result->description = description; + result->url = url; + result->photo = photo; + result->document = document; + if (App::main()) App::main()->gameUpdated(result); + } + } + } + return result; + } + LocationData *location(const LocationCoords &coords) { - LocationsData::const_iterator i = locationsData.constFind(coords); + auto i = locationsData.constFind(coords); if (i == locationsData.cend()) { i = locationsData.insert(coords, new LocationData(coords)); } @@ -1841,14 +1905,14 @@ namespace { void forgetMedia() { lastPhotos.clear(); lastPhotosMap.clear(); - for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) { - i.value()->forget(); + for_const (auto photo, ::photosData) { + photo->forget(); } - for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) { - i.value()->forget(); + for_const (auto document, ::documentsData) { + document->forget(); } - for (LocationsData::const_iterator i = ::locationsData.cbegin(), e = ::locationsData.cend(); i != e; ++i) { - i.value()->thumb->forget(); + for_const (auto location, ::locationsData) { + location->thumb->forget(); } } @@ -2041,6 +2105,7 @@ namespace { ::photoItems.clear(); ::documentItems.clear(); ::webPageItems.clear(); + ::gameItems.clear(); ::sharedContactItems.clear(); ::gifItems.clear(); lastPhotos.clear(); @@ -2464,7 +2529,7 @@ namespace { } void regPhotoItem(PhotoData *data, HistoryItem *item) { - ::photoItems[data].insert(item, NullType()); + ::photoItems[data].insert(item); } void unregPhotoItem(PhotoData *data, HistoryItem *item) { @@ -2480,7 +2545,7 @@ namespace { } void regDocumentItem(DocumentData *data, HistoryItem *item) { - ::documentItems[data].insert(item, NullType()); + ::documentItems[data].insert(item); } void unregDocumentItem(DocumentData *data, HistoryItem *item) { @@ -2496,7 +2561,7 @@ namespace { } void regWebPageItem(WebPageData *data, HistoryItem *item) { - ::webPageItems[data].insert(item, NullType()); + ::webPageItems[data].insert(item); } void unregWebPageItem(WebPageData *data, HistoryItem *item) { @@ -2507,10 +2572,22 @@ namespace { return ::webPageItems; } + void regGameItem(GameData *data, HistoryItem *item) { + ::gameItems[data].insert(item); + } + + void unregGameItem(GameData *data, HistoryItem *item) { + ::gameItems[data].remove(item); + } + + const GameItems &gameItems() { + return ::gameItems; + } + void regSharedContactItem(int32 userId, HistoryItem *item) { auto user = App::userLoaded(userId); auto canShareThisContact = user ? user->canShareThisContact() : false; - ::sharedContactItems[userId].insert(item, NullType()); + ::sharedContactItems[userId].insert(item); if (canShareThisContact != (user ? user->canShareThisContact() : false)) { Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); } @@ -2549,11 +2626,12 @@ namespace { } QString phoneFromSharedContact(int32 userId) { - SharedContactItems::const_iterator i = ::sharedContactItems.constFind(userId); + auto i = ::sharedContactItems.constFind(userId); if (i != ::sharedContactItems.cend() && !i->isEmpty()) { - HistoryMedia *media = i->cbegin().key()->getMedia(); - if (media && media->type() == MediaTypeContact) { - return static_cast(media)->phone(); + if (auto media = (*i->cbegin())->getMedia()) { + if (media->type() == MediaTypeContact) { + return static_cast(media)->phone(); + } } } return QString(); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 299caaf90a..1f4951232d 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -31,15 +31,16 @@ class FileUploader; #include "history.h" #include "layout.h" -typedef QMap HistoryItemsMap; -typedef QHash PhotoItems; -typedef QHash DocumentItems; -typedef QHash WebPageItems; -typedef QHash SharedContactItems; -typedef QHash GifItems; +using HistoryItemsMap = OrderedSet; +using PhotoItems = QHash; +using DocumentItems = QHash; +using WebPageItems = QHash; +using GameItems = QHash; +using SharedContactItems = QHash; +using GifItems = QHash; -typedef QHash PhotosData; -typedef QHash DocumentsData; +using PhotosData = QHash; +using DocumentsData = QHash; namespace App { AppClass *app(); @@ -90,14 +91,15 @@ namespace App { StorageImageLocation imageLocation(const MTPPhotoSize &size); PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); - PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0); - PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0); + PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr); + PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr); DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb); - DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0); - DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0); - WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = 0); - WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0); + DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr); + DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr); + WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr); + WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr); WebPageData *feedWebPage(const MTPWebPage &webpage); + GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr); PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded); inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { @@ -148,7 +150,9 @@ namespace App { DocumentData *document(const DocumentId &document); DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation); WebPageData *webPage(const WebPageId &webPage); - WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill); + WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill); + GameData *game(const GameId &game); + GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *doc); LocationData *location(const LocationCoords &coords); void forgetMedia(); @@ -247,6 +251,10 @@ namespace App { void unregWebPageItem(WebPageData *data, HistoryItem *item); const WebPageItems &webPageItems(); + void regGameItem(GameData *data, HistoryItem *item); + void unregGameItem(GameData *data, HistoryItem *item); + const GameItems &gameItems(); + void regSharedContactItem(int32 userId, HistoryItem *item); void unregSharedContactItem(int32 userId, HistoryItem *item); const SharedContactItems &sharedContactItems(); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 247aef93a6..8a44c4c450 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -33,8 +33,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "autoupdater.h" #include "core/observer.h" #include "observer_peer.h" -#include "core/observer.h" #include "window/chat_background.h" +#include "history/history_location_manager.h" namespace { void mtpStateChanged(int32 dc, int32 state) { @@ -744,7 +744,7 @@ AppClass::AppClass() : QObject() Shortcuts::start(); - initImageLinkManager(); + initLocationManager(); App::initMedia(); Local::ReadMapState state = Local::readMap(QByteArray()); @@ -1095,7 +1095,7 @@ AppClass::~AppClass() { stopWebLoadManager(); App::deinitMedia(); - deinitImageLinkManager(); + deinitLocationManager(); MTP::finish(); diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index 8075d8b57d..755221c49c 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "connectionbox.h" #include "mainwidget.h" #include "mainwindow.h" +#include "history/history_location_manager.h" ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth) , _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), Global::ConnectionProxy().host) @@ -207,7 +208,7 @@ void ConnectionBox::onSave() { Global::RefConnectionTypeChanged().notify(); MTP::restart(); - reinitImageLinkManager(); + reinitLocationManager(); reinitWebLoadManager(); onClose(); } diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 59281428e5..2259c1e092 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_indexed_list.h" #include "styles/style_dialogs.h" #include "history/history_service_layout.h" +#include "history/history_location_manager.h" #include "data/data_drafts.h" #include "media/media_clip_reader.h" #include "lang.h" @@ -786,6 +787,12 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, default: badMedia = 1; break; } break; + case mtpc_messageMediaGame: + switch (m.vmedia.c_messageMediaGame().vgame.type()) { + case mtpc_game: break; + default: badMedia = 1; break; + } + break; case mtpc_messageMediaUnsupported: default: badMedia = 1; break; } @@ -2590,18 +2597,7 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '-'); - }; - for (auto &ch : start) { - if (!charIsGoodForStartParam(ch)) { - ch = '_'; - } - } - auto strData = QString::number(buttonData.vgame_id.v) + ',' + start + ',' + title; - buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), strData.toUtf8(), 0 }); + buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), QByteArray(), 0 }); } break; } } @@ -2889,7 +2885,7 @@ bool HistoryItem::canEdit(const QDateTime &cur) const { if (auto msg = toHistoryMessage()) { if (msg->Has() || msg->Has()) return false; - if (HistoryMedia *media = msg->getMedia()) { + if (auto media = msg->getMedia()) { auto type = media->type(); if (type != MediaTypePhoto && type != MediaTypeVideo && @@ -3428,6 +3424,7 @@ int HistoryPhoto::resizeGetHeight(int width) { void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; + p.fillRect(QRect(0, 0, _width, _height), QColor(128, 255, 128)); _data->automaticLoad(_parent); bool selected = (selection == FullSelection); @@ -3579,11 +3576,11 @@ HistoryTextState HistoryPhoto::getState(int x, int y, HistoryStateRequest reques void HistoryPhoto::updateSentMedia(const MTPMessageMedia &media) { if (media.type() == mtpc_messageMediaPhoto) { - const auto &photo(media.c_messageMediaPhoto().vphoto); + auto &photo = media.c_messageMediaPhoto().vphoto; App::feedPhoto(photo, _data); if (photo.type() == mtpc_photo) { - const auto &sizes(photo.c_photo().vsizes.c_vector().v); + auto &sizes = photo.c_photo().vsizes.c_vector().v; int32 max = 0; const MTPDfileLocation *maxLocation = 0; for (int32 i = 0, l = sizes.size(); i < l; ++i) { @@ -5428,24 +5425,16 @@ namespace { } int32 _lineHeight = 0; -} +} // namespace HistoryWebPage::HistoryWebPage(HistoryItem *parent, WebPageData *data) : HistoryMedia(parent) , _data(data) -, _openl(0) -, _attach(nullptr) -, _asArticle(false) , _title(st::msgMinWidth - st::webPageLeft) -, _description(st::msgMinWidth - st::webPageLeft) -, _siteNameWidth(0) -, _durationWidth(0) -, _pixw(0) -, _pixh(0) { +, _description(st::msgMinWidth - st::webPageLeft) { } HistoryWebPage::HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other) : HistoryMedia(parent) , _data(other._data) -, _openl(0) , _attach(other._attach ? other._attach->clone(parent) : nullptr) , _asArticle(other._asArticle) , _title(other._title) @@ -5489,16 +5478,16 @@ void HistoryWebPage::initDimensions() { if (!_asArticle && !_attach) { if (_data->document) { if (_data->document->sticker()) { - _attach = new HistorySticker(_parent, _data->document); + _attach = std_::make_unique(_parent, _data->document); } else if (_data->document->isAnimation()) { - _attach = new HistoryGif(_parent, _data->document, QString()); + _attach = std_::make_unique(_parent, _data->document, QString()); } else if (_data->document->isVideo()) { - _attach = new HistoryVideo(_parent, _data->document, QString()); + _attach = std_::make_unique(_parent, _data->document, QString()); } else { - _attach = new HistoryDocument(_parent, _data->document, QString()); + _attach = std_::make_unique(_parent, _data->document, QString()); } } else if (_data->photo) { - _attach = new HistoryPhoto(_parent, _data->photo, QString()); + _attach = std_::make_unique(_parent, _data->photo, QString()); } } @@ -5911,218 +5900,280 @@ ImagePtr HistoryWebPage::replyPreview() { return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr()); } -HistoryWebPage::~HistoryWebPage() { - deleteAndMark(_attach); +HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent) +, _data(data) +, _title(st::msgMinWidth - st::webPageLeft) +, _description(st::msgMinWidth - st::webPageLeft) { } -namespace { - LocationManager *locationManager = nullptr; +HistoryGame::HistoryGame(HistoryItem *parent, const HistoryGame &other) : HistoryMedia(parent) +, _data(other._data) +, _attach(other._attach ? other._attach->clone(parent) : nullptr) +, _title(other._title) +, _description(other._description) { } -void LocationManager::init() { - if (manager) delete manager; - manager = new QNetworkAccessManager(); - App::setProxySettings(*manager); +void HistoryGame::initDimensions() { + if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height); - connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*))); -#ifndef OS_MAC_OLD - connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList&)), this, SLOT(onFailed(QNetworkReply*))); -#endif // OS_MAC_OLD - connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); + if (!_openl && !_data->url.isEmpty()) _openl.reset(new UrlClickHandler(_data->url, true)); - if (black) { - delete black->v(); - delete black; - } - QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); - { - QPainter p(&b); - p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b); - } - QPixmap p = App::pixmapFromImageInPlace(std_::move(b)); - p.setDevicePixelRatio(cRetinaFactor()); - black = new ImagePtr(p, "PNG"); -} + auto title = _data->title; -void LocationManager::reinit() { - if (manager) App::setProxySettings(*manager); -} - -void LocationManager::deinit() { - if (manager) { - delete manager; - manager = nullptr; - } - if (black) { - delete black->v(); - delete black; - black = nullptr; - } - dataLoadings.clear(); - imageLoadings.clear(); -} - -void initImageLinkManager() { - if (!locationManager) { - locationManager = new LocationManager(); - locationManager->init(); - } -} - -void reinitImageLinkManager() { - if (locationManager) { - locationManager->reinit(); - } -} - -void deinitImageLinkManager() { - if (locationManager) { - locationManager->deinit(); - delete locationManager; - locationManager = nullptr; - } -} - -void LocationManager::getData(LocationData *data) { - if (!manager) { - DEBUG_LOG(("App Error: getting image link data without manager init!")); - return failed(data); - } - - int32 w = st::locationSize.width(), h = st::locationSize.height(); - int32 zoom = 13, scale = 1; - if (cScale() == dbisTwo || cRetina()) { - scale = 2; - } else { - w = convertScale(w); - h = convertScale(h); - } - QString coords = qsl("%1,%2").arg(data->coords.lat).arg(data->coords.lon); - QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); - QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url))); - imageLoadings[reply] = data; -} - -void LocationManager::onFinished(QNetworkReply *reply) { - if (!manager) return; - if (reply->error() != QNetworkReply::NoError) return onFailed(reply); - - QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (statusCode.isValid()) { - int status = statusCode.toInt(); - if (status == 301 || status == 302) { - QString loc = reply->header(QNetworkRequest::LocationHeader).toString(); - if (!loc.isEmpty()) { - QMap::iterator i = dataLoadings.find(reply); - if (i != dataLoadings.cend()) { - LocationData *d = i.value(); - if (serverRedirects.constFind(d) == serverRedirects.cend()) { - serverRedirects.insert(d, 1); - } else if (++serverRedirects[d] > MaxHttpRedirects) { - DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc)); - return onFailed(reply); - } - dataLoadings.erase(i); - dataLoadings.insert(manager->get(QNetworkRequest(loc)), d); - return; - } else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) { - LocationData *d = i.value(); - if (serverRedirects.constFind(d) == serverRedirects.cend()) { - serverRedirects.insert(d, 1); - } else if (++serverRedirects[d] > MaxHttpRedirects) { - DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc)); - return onFailed(reply); - } - imageLoadings.erase(i); - imageLoadings.insert(manager->get(QNetworkRequest(loc)), d); - return; - } + // init attach + if (!_attach) { + if (_data->document) { + if (_data->document->sticker()) { + _attach = std_::make_unique(_parent, _data->document); + } else if (_data->document->isAnimation()) { + _attach = std_::make_unique(_parent, _data->document, QString()); + } else if (_data->document->isVideo()) { + _attach = std_::make_unique(_parent, _data->document, QString()); + } else { + _attach = std_::make_unique(_parent, _data->document, QString()); } - } - if (status != 200) { - DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status)); - return onFailed(reply); + } else if (_data->photo) { + _attach = std_::make_unique(_parent, _data->photo, QString()); } } - LocationData *d = 0; - QMap::iterator i = dataLoadings.find(reply); - if (i != dataLoadings.cend()) { - d = i.value(); - dataLoadings.erase(i); - - QJsonParseError e; - QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e); - if (e.error != QJsonParseError::NoError) { - DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link")); - return onFailed(reply); + // init strings + if (_description.isEmpty() && !_data->description.isEmpty()) { + auto text = textClean(_data->description); + if (text.isEmpty()) { + _data->description = QString(); + } else { + _description.setText(st::webPageDescriptionFont, text, _webpageDescriptionOptions); } - failed(d); + } + if (_title.isEmpty() && !title.isEmpty()) { + title = textOneLine(textClean(title)); + if (title.isEmpty()) { + _data->title = QString(); + } else { + _title.setText(st::webPageTitleFont, title, _webpageTitleOptions); + } + } - if (App::main()) App::main()->update(); + // init dimensions + int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right(); + int32 skipBlockWidth = _parent->skipBlockWidth(); + _maxw = skipBlockWidth; + _minh = st::msgPadding.top(); + + int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight; + int32 descMaxLines = (4 + (titleMinHeight ? 0 : 1)); + int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight); + + if (!_title.isEmpty()) { + _maxw = qMax(_maxw, int32(_title.maxWidth())); + _minh += titleMinHeight; + } + if (!_description.isEmpty()) { + _maxw = qMax(_maxw, int32(_description.maxWidth())); + _minh += descriptionMinHeight; + } + if (_attach) { + if (_minh) _minh += st::webPagePhotoSkip; + _attach->initDimensions(); + QMargins bubble(_attach->bubbleMargins()); + _maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top())); + _minh += _attach->minHeight() - bubble.top() - bubble.bottom(); + } + _maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); +} + +int HistoryGame::resizeGetHeight(int width) { + _width = qMin(width, _maxw); + width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); + + int32 linesMax = 5; + _height = st::msgPadding.top(); + if (_title.isEmpty()) { + _titleLines = 0; } else { - i = imageLoadings.find(reply); - if (i != imageLoadings.cend()) { - d = i.value(); - imageLoadings.erase(i); - - QPixmap thumb; - QByteArray format; - QByteArray data(reply->readAll()); - { - QBuffer buffer(&data); - QImageReader reader(&buffer); -#ifndef OS_MAC_OLD - reader.setAutoTransform(true); -#endif // OS_MAC_OLD - thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly); - format = reader.format(); - thumb.setDevicePixelRatio(cRetinaFactor()); - if (format.isEmpty()) format = QByteArray("JPG"); - } - d->loading = false; - d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format); - serverRedirects.remove(d); - if (App::main()) App::main()->update(); + if (_title.countHeight(width) < 2 * st::webPageTitleFont->height) { + _titleLines = 1; + } else { + _titleLines = 2; } + _height += _titleLines * _lineHeight; } -} -void LocationManager::onFailed(QNetworkReply *reply) { - if (!manager) return; - - LocationData *d = 0; - QMap::iterator i = dataLoadings.find(reply); - if (i != dataLoadings.cend()) { - d = i.value(); - dataLoadings.erase(i); + if (_description.isEmpty()) { + _descriptionLines = 0; } else { - i = imageLoadings.find(reply); - if (i != imageLoadings.cend()) { - d = i.value(); - imageLoadings.erase(i); + int32 descriptionHeight = _description.countHeight(width); + if (descriptionHeight < (linesMax - _titleLines) * st::webPageDescriptionFont->height) { + _descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height); + } else { + _descriptionLines = (linesMax - _titleLines); + } + _height += _descriptionLines * _lineHeight; + } + + if (_attach) { + if (_height) _height += st::webPagePhotoSkip; + + QMargins bubble(_attach->bubbleMargins()); + + _attach->resizeGetHeight(width + bubble.left() + bubble.right()); + _height += _attach->height() - bubble.top() - bubble.bottom(); + } + + return _height; +} + +void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = _width, height = _height; + + bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; + bool selected = (selection == FullSelection); + + style::color barfg = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); + style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); + + int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0; + width -= lshift + rshift; + QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); + + QRect bar(rtlrect(st::msgPadding.left(), st::msgPadding.top(), st::webPageBar, _height - bshift, _width)); + p.fillRect(bar, barfg); + + int32 tshift = st::msgPadding.top(); + if (_titleLines) { + p.setPen(st::black); + int32 endskip = 0; + if (_title.hasSkipBlock()) { + endskip = _parent->skipBlockWidth(); + } + _title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection); + tshift += _titleLines * _lineHeight; + } + if (_descriptionLines) { + p.setPen(st::black); + int32 endskip = 0; + if (_description.hasSkipBlock()) { + endskip = _parent->skipBlockWidth(); + } + _description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection)); + tshift += _descriptionLines * _lineHeight; + } + if (_attach) { + if (tshift) tshift += st::webPagePhotoSkip; + + int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); + if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); + + auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; + + p.translate(attachLeft, attachTop); + _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); + p.translate(-attachLeft, -attachTop); + } +} + +HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; + int32 width = _width, height = _height; + + int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0; + width -= lshift + rshift; + QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); + + bool inThumb = false; + int tshift = st::msgPadding.top(), symbolAdd = 0; + if (_titleLines) { + if (y >= tshift && y < tshift + _titleLines * _lineHeight) { + Text::StateRequestElided titleRequest = request.forText(); + titleRequest.lines = _titleLines; + result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest); + } else if (y >= tshift + _titleLines * _lineHeight) { + symbolAdd += _title.length(); + } + tshift += _titleLines * _lineHeight; + } + if (_descriptionLines) { + if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) { + Text::StateRequestElided descriptionRequest = request.forText(); + descriptionRequest.lines = _descriptionLines; + result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest); + } else if (y >= tshift + _descriptionLines * _lineHeight) { + symbolAdd += _description.length(); + } + tshift += _descriptionLines * _lineHeight; + } + if (inThumb) { + result.link = _openl; + } else if (_attach) { + if (tshift) tshift += st::webPagePhotoSkip; + + if (x >= lshift && x < lshift + width && y >= tshift && y < _height) { + result.link = _openl; } } - DEBUG_LOG(("Network Error: failed to get data for image link %1,%2 error %3").arg(d ? d->coords.lat : 0).arg(d ? d->coords.lon : 0).arg(reply->errorString())); - if (d) { - failed(d); + + result.symbol += symbolAdd; + return result; +} + +TextSelection HistoryGame::adjustSelection(TextSelection selection, TextSelectType type) const { + if (!_descriptionLines || selection.to <= _title.length()) { + return _title.adjustSelection(selection, type); + } + auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); + if (selection.from >= _title.length()) { + return fromDescriptionSelection(descriptionSelection); + } + auto titleSelection = _title.adjustSelection(selection, type); + return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; +} + +void HistoryGame::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { + if (_attach) { + _attach->clickHandlerActiveChanged(p, active); } } -void LocationManager::failed(LocationData *data) { - data->loading = false; - data->thumb = *black; - serverRedirects.remove(data); +void HistoryGame::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { + if (_attach) { + _attach->clickHandlerPressedChanged(p, pressed); + } } -void LocationData::load() { - if (!thumb->isNull()) return thumb->load(false, false); - if (loading) return; +void HistoryGame::attachToParent() { + App::regGameItem(_data, _parent); + if (_attach) _attach->attachToParent(); +} - loading = true; - if (locationManager) { - locationManager->getData(this); +void HistoryGame::detachFromParent() { + App::unregGameItem(_data, _parent); + if (_attach) _attach->detachFromParent(); +} + +TextWithEntities HistoryGame::selectedText(TextSelection selection) const { + if (selection == FullSelection) { + return TextWithEntities(); } + auto titleResult = _title.originalTextWithEntities(selection, ExpandLinksAll); + auto descriptionResult = _description.originalTextWithEntities(toDescriptionSelection(selection), ExpandLinksAll); + if (titleResult.text.isEmpty()) { + return descriptionResult; + } else if (descriptionResult.text.isEmpty()) { + return titleResult; + } + + titleResult.text += '\n'; + appendTextWithEntities(titleResult, std_::move(descriptionResult)); + return titleResult; +} + +ImagePtr HistoryGame::replyPreview() { + return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr()); } HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent) @@ -6907,35 +6958,35 @@ void HistoryMessage::initTime() { void HistoryMessage::initMedia(const MTPMessageMedia *media, QString ¤tText) { switch (media ? media->type() : mtpc_messageMediaEmpty) { case mtpc_messageMediaContact: { - const auto &d(media->c_messageMediaContact()); + auto &d = media->c_messageMediaContact(); _media.reset(new HistoryContact(this, d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number))); } break; case mtpc_messageMediaGeo: { - const auto &point(media->c_messageMediaGeo().vgeo); + auto &point = media->c_messageMediaGeo().vgeo; if (point.type() == mtpc_geoPoint) { _media.reset(new HistoryLocation(this, LocationCoords(point.c_geoPoint()))); } } break; case mtpc_messageMediaVenue: { - const auto &d(media->c_messageMediaVenue()); + auto &d = media->c_messageMediaVenue(); if (d.vgeo.type() == mtpc_geoPoint) { _media.reset(new HistoryLocation(this, LocationCoords(d.vgeo.c_geoPoint()), qs(d.vtitle), qs(d.vaddress))); } } break; case mtpc_messageMediaPhoto: { - const auto &photo(media->c_messageMediaPhoto()); + auto &photo = media->c_messageMediaPhoto(); if (photo.vphoto.type() == mtpc_photo) { _media.reset(new HistoryPhoto(this, App::feedPhoto(photo.vphoto.c_photo()), qs(photo.vcaption))); } } break; case mtpc_messageMediaDocument: { - const auto &document(media->c_messageMediaDocument().vdocument); + auto &document = media->c_messageMediaDocument().vdocument; if (document.type() == mtpc_document) { return initMediaFromDocument(App::feedDocument(document), qs(media->c_messageMediaDocument().vcaption)); } } break; case mtpc_messageMediaWebPage: { - const auto &d(media->c_messageMediaWebPage().vwebpage); + auto &d = media->c_messageMediaWebPage().vwebpage; switch (d.type()) { case mtpc_webPageEmpty: break; case mtpc_webPagePending: { @@ -6946,6 +6997,12 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media, QString ¤tTex } break; } } break; + case mtpc_messageMediaGame: { + auto &d = media->c_messageMediaGame().vgame; + if (d.type() == mtpc_game) { + _media.reset(new HistoryGame(this, App::feedGame(d.c_game()))); + } + } break; }; } @@ -6979,7 +7036,7 @@ void HistoryMessage::initDimensions() { if (_media) { _media->initDimensions(); - if (_media->isDisplayed()) { + if (_media->isDisplayed() && !_media->isAboveMessage()) { if (_text.hasSkipBlock()) { _text.removeSkipBlock(); _textWidth = -1; @@ -6993,7 +7050,7 @@ void HistoryMessage::initDimensions() { } _maxw = plainMaxWidth(); - if (_text.isEmpty()) { + if (emptyText()) { _minh = 0; } else { _minh = st::msgPadding.top() + _text.minHeight() + st::msgPadding.bottom(); @@ -7031,7 +7088,7 @@ void HistoryMessage::initDimensions() { _maxw = st::msgMinWidth; _minh = 0; } - if (reply && !_text.isEmpty()) { + if (reply && !emptyText()) { int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); if (reply->_replyToVia) { replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth; @@ -7045,7 +7102,7 @@ void HistoryMessage::initDimensions() { // if we have a text bubble we can resize it to fit the keyboard // but if we have only media we don't do that - if (!_text.isEmpty()) { + if (!emptyText()) { _maxw = qMax(_maxw, markup->inlineKeyboard->naturalWidth()); } } @@ -7132,6 +7189,9 @@ void HistoryMessage::applyEditionToEmpty() { } void HistoryMessage::updateMedia(const MTPMessageMedia *media) { + auto setMediaAllowed = [](HistoryMediaType type) { + return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation); + }; if (_flags & MTPDmessage_ClientFlag::f_from_inline_bot) { bool needReSet = true; if (media && _media) { @@ -7141,7 +7201,7 @@ void HistoryMessage::updateMedia(const MTPMessageMedia *media) { setMedia(media); } _flags &= ~MTPDmessage_ClientFlag::f_from_inline_bot; - } else if (media && _media && _media->type() != MediaTypeWebPage) { + } else if (media && _media && !setMediaAllowed(_media->type())) { _media->updateSentMedia(*media); } else { setMedia(media); @@ -7228,18 +7288,18 @@ TextWithEntities HistoryMessage::selectedText(TextSelection selection) const { void HistoryMessage::setMedia(const MTPMessageMedia *media) { if (!_media && (!media || media->type() == mtpc_messageMediaEmpty)) return; - bool mediaWasDisplayed = false; + bool mediaRemovedSkipBlock = false; if (_media) { - mediaWasDisplayed = _media->isDisplayed(); + mediaRemovedSkipBlock = _media->isDisplayed() && !_media->isAboveMessage(); _media.clear(); } QString t; initMedia(media, t); - if (_media && _media->isDisplayed() && !mediaWasDisplayed) { + if (_media && _media->isDisplayed() && !_media->isAboveMessage() && !mediaRemovedSkipBlock) { _text.removeSkipBlock(); _textWidth = -1; _textHeight = 0; - } else if (mediaWasDisplayed && (!_media || !_media->isDisplayed())) { + } else if (mediaRemovedSkipBlock && (!_media || !_media->isDisplayed() || _media->isAboveMessage())) { _text.setSkipBlock(skipBlockWidth(), skipBlockHeight()); _textWidth = -1; _textHeight = 0; @@ -7248,7 +7308,7 @@ void HistoryMessage::setMedia(const MTPMessageMedia *media) { void HistoryMessage::setText(const TextWithEntities &textWithEntities) { textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - if (_media && _media->isDisplayed()) { + if (_media && _media->isDisplayed() && !_media->isAboveMessage()) { _text.setMarkedText(st::msgFont, textWithEntities, itemTextOptions(this)); } else { _text.setMarkedText(st::msgFont, { textWithEntities.text + skipBlock(), textWithEntities.entities }, itemTextOptions(this)); @@ -7492,7 +7552,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); - if (const ReplyKeyboard *keyboard = inlineReplyKeyboard()) { + if (auto keyboard = inlineReplyKeyboard()) { int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); height -= h; int top = height + st::msgBotKbButton.margin - marginBottom(); @@ -7502,8 +7562,6 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u } if (bubble) { - auto fwd = Get(); - auto via = Get(); if (displayFromName() && author()->nameVersion > _authorNameVersion) { fromNameUpdated(width); } @@ -7516,40 +7574,35 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, r, bg, cors, &sh); - if (displayFromName()) { - p.setFont(st::msgNameFont); - if (isPost()) { - p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); - } else { - p.setPen(author()->color); - } - author()->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right()); - if (via && !fwd && width > st::msgPadding.left() + st::msgPadding.right() + author()->nameText.maxWidth() + st::msgServiceFont->spacew) { - p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - p.drawText(r.left() + st::msgPadding.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, r.top() + st::msgPadding.top() + st::msgServiceFont->ascent, via->_text); - } - r.setTop(r.top() + st::msgNameFont->height); - } - QRect trect(r.marginsAdded(-st::msgPadding)); - + paintFromName(p, trect, selected); paintForwardedInfo(p, trect, selected); paintReplyInfo(p, trect, selected); paintViaBotIdInfo(p, trect, selected); - p.setPen(st::msgColor); - p.setFont(st::msgFont); - _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection); - + auto needDrawInfo = true; if (_media && _media->isDisplayed()) { - int32 top = height - marginBottom() - _media->height(); - p.translate(left, top); - _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); - p.translate(-left, -top); - if (!_media->customInfoLayout()) { - HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); + auto mediaAboveText = _media->isAboveMessage(); + auto mediaHeight = _media->height(); + auto mediaLeft = trect.x() - st::msgPadding.left(); + auto mediaTop = mediaAboveText ? (trect.y() - st::msgPadding.top()) : (r.y() + r.height() - mediaHeight); + if (!mediaAboveText) { + paintText(p, trect, selection); } + p.translate(mediaLeft, mediaTop); + _media->draw(p, r.translated(-mediaLeft, -mediaTop), toMediaSelection(selection), ms); + p.translate(-mediaLeft, -mediaTop); + + if (mediaAboveText) { + trect.setY(trect.y() + mediaHeight); + paintText(p, trect, selection); + } + + needDrawInfo = !_media->customInfoLayout(); } else { + paintText(p, trect, selection); + } + if (needDrawInfo) { HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); } } else if (_media) { @@ -7567,6 +7620,27 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u } } +void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const { + if (displayFromName()) { + p.setFont(st::msgNameFont); + if (isPost()) { + p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); + } else { + p.setPen(author()->color); + } + author()->nameText.drawElided(p, trect.left(), trect.top(), trect.width()); + + auto fwd = Get(); + auto via = Get(); + if (via && !fwd && trect.width() > author()->nameText.maxWidth() + st::msgServiceFont->spacew) { + bool outbg = out() && !isPost(); + p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + p.drawText(trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, trect.top() + st::msgServiceFont->ascent, via->_text); + } + trect.setY(trect.y() + st::msgNameFont->height); + } +} + void HistoryMessage::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const { if (displayForwardedFrom()) { style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont); @@ -7609,6 +7683,12 @@ void HistoryMessage::paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) } } +void HistoryMessage::paintText(Painter &p, QRect &trect, TextSelection selection) const { + p.setPen(st::msgColor); + p.setFont(st::msgFont); + _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection); +} + void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) { if (auto reply = Get()) { reply->itemRemoved(this, dependency); @@ -7655,7 +7735,7 @@ int HistoryMessage::performResizeGetHeight(int width) { _height = _minh; if (media) _media->resizeGetHeight(_maxw); } else { - if (_text.isEmpty()) { + if (emptyText()) { _height = 0; } else { int32 textWidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 1); @@ -7670,24 +7750,27 @@ int HistoryMessage::performResizeGetHeight(int width) { if (media) _height += _media->resizeGetHeight(width); } + auto mediaTopPaddingAdded = !emptyText(); if (displayFromName()) { - if (emptyText()) { - _height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip; - } else { - _height += st::msgNameFont->height; - } int32 l = 0, w = 0; countPositionAndSize(l, w); fromNameUpdated(w); + + if (!mediaTopPaddingAdded) { + _height += st::msgPadding.top() + st::mediaHeaderSkip; + mediaTopPaddingAdded = true; + } + _height += st::msgNameFont->height; } else if (via && !fwd) { int32 l = 0, w = 0; countPositionAndSize(l, w); via->resize(w - st::msgPadding.left() - st::msgPadding.right()); - if (emptyText() && !displayFromName()) { - _height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip; - } else { - _height += st::msgNameFont->height; + + if (!mediaTopPaddingAdded) { + _height += st::msgPadding.top() + st::mediaHeaderSkip; + mediaTopPaddingAdded = true; } + _height += st::msgNameFont->height; } if (displayForwardedFrom()) { @@ -7695,23 +7778,23 @@ int HistoryMessage::performResizeGetHeight(int width) { countPositionAndSize(l, w); int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height; - if (emptyText() && !displayFromName()) { - _height += st::msgPadding.top() + fwdheight + st::mediaHeaderSkip; - } else { - _height += fwdheight; + if (!mediaTopPaddingAdded) { + _height += st::msgPadding.top() + st::mediaHeaderSkip; + mediaTopPaddingAdded = true; } + _height += fwdheight; } if (reply) { int32 l = 0, w = 0; countPositionAndSize(l, w); - - if (emptyText() && !displayFromName() && !Has()) { - _height += st::msgPadding.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom() + st::mediaHeaderSkip; - } else { - _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - } reply->resize(w - st::msgPadding.left() - st::msgPadding.right()); + + if (!mediaTopPaddingAdded) { + _height += st::msgPadding.top() + st::mediaHeaderSkip; + mediaTopPaddingAdded = true; + } + _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); } } else if (_media) { _height = _media->resizeGetHeight(width); @@ -8154,25 +8237,9 @@ bool HistoryService::prepareGameScoreText(const QString &from, QString *outText, auto gamescore = Get(); if (gamescore && gamescore->msg) { auto getGameTitle = [item = gamescore->msg, &second]() -> QString { - if (auto markup = item->Get()) { - for (int i = 0, rowsCount = markup->rows.size(); i != rowsCount; ++i) { - auto &row = markup->rows[i]; - for (int j = 0, buttonsCount = row.size(); j != buttonsCount; ++j) { - auto &button = row[j]; - if (button.type == HistoryMessageReplyMarkup::Button::Type::Game) { - auto strData = QString::fromUtf8(button.data); - second = MakeShared(item, i, j); - auto parts = strData.split(','); - t_assert(parts.size() > 2); - QString gameTitle; - gameTitle.reserve(strData.size() - 2); - gameTitle.append(parts[2]); - for (int i = 3, count = parts.size(); i != count; ++i) { - gameTitle.append(',').append(parts[i]); - } - return textcmdLink(2, gameTitle); - } - } + if (auto media = item->getMedia()) { + if (media->type() == MediaTypeGame) { + return static_cast(media)->game()->title; } } return lang(lng_deleted_message); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index ecba44ef3e..91d1d263ec 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -100,6 +100,7 @@ enum HistoryMediaType { MediaTypeWebPage, MediaTypeMusicFile, MediaTypeVoiceFile, + MediaTypeGame, MediaTypeCount }; @@ -1617,6 +1618,9 @@ public: virtual bool isDisplayed() const { return true; } + virtual bool isAboveMessage() const { + return false; + } virtual bool hasTextForCopy() const { return false; } @@ -2408,11 +2412,9 @@ public: } HistoryMedia *attach() const { - return _attach; + return _attach.get(); } - ~HistoryWebPage(); - private: TextSelection toDescriptionSelection(TextSelection selection) const { return internal::unshiftSelection(selection, _title); @@ -2423,51 +2425,114 @@ private: WebPageData *_data; ClickHandlerPtr _openl; - HistoryMedia *_attach; + std_::unique_ptr _attach; - bool _asArticle; + bool _asArticle = false; int32 _titleLines, _descriptionLines; Text _title, _description; - int32 _siteNameWidth; + int32 _siteNameWidth = 0; QString _duration; - int32 _durationWidth; + int32 _durationWidth = 0; - int16 _pixw, _pixh; + int16 _pixw = 0; + int16 _pixh = 0; }; -void initImageLinkManager(); -void reinitImageLinkManager(); -void deinitImageLinkManager(); +class HistoryGame : public HistoryMedia { +public: + HistoryGame(HistoryItem *parent, GameData *data); + HistoryGame(HistoryItem *parent, const HistoryGame &other); + HistoryMediaType type() const override { + return MediaTypeGame; + } + HistoryGame *clone(HistoryItem *newParent) const override { + return new HistoryGame(newParent, *this); + } + + void initDimensions() override; + int resizeGetHeight(int width) override; + + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override; + bool isAboveMessage() const override { + return true; + } + bool hasTextForCopy() const override { + return false; // we do not add _title and _description in FullSelection text copy. + } + + bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { + return _attach && _attach->toggleSelectionByHandlerClick(p); + } + bool dragItemByHandler(const ClickHandlerPtr &p) const override { + return _attach && _attach->dragItemByHandler(p); + } + + TextWithEntities selectedText(TextSelection selection) const override; + + void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; + void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; + + DocumentData *getDocument() override { + return _attach ? _attach->getDocument() : nullptr; + } + Media::Clip::Reader *getClipReader() override { + return _attach ? _attach->getClipReader() : nullptr; + } + bool playInline(bool autoplay) override { + return _attach ? _attach->playInline(autoplay) : false; + } + void stopInline() override { + if (_attach) _attach->stopInline(); + } + + void attachToParent() override; + void detachFromParent() override; + + bool hasReplyPreview() const override { + return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull()); + } + ImagePtr replyPreview() override; + + GameData *game() { + return _data; + } + + bool needsBubble() const override { + return true; + } + bool customInfoLayout() const override { + return false; + } + + HistoryMedia *attach() const { + return _attach.get(); + } + +private: + TextSelection toDescriptionSelection(TextSelection selection) const { + return internal::unshiftSelection(selection, _title); + } + TextSelection fromDescriptionSelection(TextSelection selection) const { + return internal::shiftSelection(selection, _title); + } + + GameData *_data; + ClickHandlerPtr _openl; + std_::unique_ptr _attach; + + int32 _titleLines, _descriptionLines; + + Text _title, _description; + +}; struct LocationCoords; struct LocationData; -class LocationManager : public QObject { - Q_OBJECT -public: - void init(); - void reinit(); - void deinit(); - - void getData(LocationData *data); - - ~LocationManager() { - deinit(); - } - -public slots: - void onFinished(QNetworkReply *reply); - void onFailed(QNetworkReply *reply); - -private: - void failed(LocationData *data); - - QNetworkAccessManager *manager = nullptr; - QMap dataLoadings, imageLoadings; - QMap serverRedirects; - ImagePtr *black = nullptr; -}; class HistoryLocation : public HistoryMedia { public: @@ -2703,13 +2768,15 @@ private: } return false; } - + void paintFromName(Painter &p, QRect &trect, bool selected) const; void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const; void paintReplyInfo(Painter &p, QRect &trect, bool selected) const; // this method draws "via @bot" if it is not painted in forwarded info or in from name void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const; + void paintText(Painter &p, QRect &trect, TextSelection selection) const; + void setMedia(const MTPMessageMedia *media); void setReplyMarkup(const MTPReplyMarkup *markup); diff --git a/Telegram/SourceFiles/history/history_location_manager.cpp b/Telegram/SourceFiles/history/history_location_manager.cpp new file mode 100644 index 0000000000..ee90d67345 --- /dev/null +++ b/Telegram/SourceFiles/history/history_location_manager.cpp @@ -0,0 +1,251 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "history/history_location_manager.h" + +#include "mainwidget.h" +#include "lang.h" +#include "pspecific.h" + +QString LocationClickHandler::copyToClipboardContextItemText() const { + return lang(lng_context_copy_link); +} + +void LocationClickHandler::onClick(Qt::MouseButton button) const { + if (!psLaunchMaps(_coords)) { + QDesktopServices::openUrl(_text); + } +} + +void LocationClickHandler::setup() { + QString latlon(qsl("%1,%2").arg(_coords.lat).arg(_coords.lon)); + _text = qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16"); +} + +namespace { +LocationManager *locationManager = nullptr; +} // namespace + +void initLocationManager() { + if (!locationManager) { + locationManager = new LocationManager(); + locationManager->init(); + } +} + +void reinitLocationManager() { + if (locationManager) { + locationManager->reinit(); + } +} + +void deinitLocationManager() { + if (locationManager) { + locationManager->deinit(); + delete locationManager; + locationManager = nullptr; + } +} + +void LocationManager::init() { + if (manager) delete manager; + manager = new QNetworkAccessManager(); + App::setProxySettings(*manager); + + connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*))); +#ifndef OS_MAC_OLD + connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList&)), this, SLOT(onFailed(QNetworkReply*))); +#endif // OS_MAC_OLD + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); + + if (black) { + delete black->v(); + delete black; + } + QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&b); + p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b); + } + QPixmap p = App::pixmapFromImageInPlace(std_::move(b)); + p.setDevicePixelRatio(cRetinaFactor()); + black = new ImagePtr(p, "PNG"); +} + +void LocationManager::reinit() { + if (manager) App::setProxySettings(*manager); +} + +void LocationManager::deinit() { + if (manager) { + delete manager; + manager = nullptr; + } + if (black) { + delete black->v(); + delete black; + black = nullptr; + } + dataLoadings.clear(); + imageLoadings.clear(); +} + +void LocationManager::getData(LocationData *data) { + if (!manager) { + DEBUG_LOG(("App Error: getting image link data without manager init!")); + return failed(data); + } + + int32 w = st::locationSize.width(), h = st::locationSize.height(); + int32 zoom = 13, scale = 1; + if (cScale() == dbisTwo || cRetina()) { + scale = 2; + } else { + w = convertScale(w); + h = convertScale(h); + } + QString coords = qsl("%1,%2").arg(data->coords.lat).arg(data->coords.lon); + QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); + QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url))); + imageLoadings[reply] = data; +} + +void LocationManager::onFinished(QNetworkReply *reply) { + if (!manager) return; + if (reply->error() != QNetworkReply::NoError) return onFailed(reply); + + QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (statusCode.isValid()) { + int status = statusCode.toInt(); + if (status == 301 || status == 302) { + QString loc = reply->header(QNetworkRequest::LocationHeader).toString(); + if (!loc.isEmpty()) { + QMap::iterator i = dataLoadings.find(reply); + if (i != dataLoadings.cend()) { + LocationData *d = i.value(); + if (serverRedirects.constFind(d) == serverRedirects.cend()) { + serverRedirects.insert(d, 1); + } else if (++serverRedirects[d] > MaxHttpRedirects) { + DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc)); + return onFailed(reply); + } + dataLoadings.erase(i); + dataLoadings.insert(manager->get(QNetworkRequest(loc)), d); + return; + } else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) { + LocationData *d = i.value(); + if (serverRedirects.constFind(d) == serverRedirects.cend()) { + serverRedirects.insert(d, 1); + } else if (++serverRedirects[d] > MaxHttpRedirects) { + DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc)); + return onFailed(reply); + } + imageLoadings.erase(i); + imageLoadings.insert(manager->get(QNetworkRequest(loc)), d); + return; + } + } + } + if (status != 200) { + DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status)); + return onFailed(reply); + } + } + + LocationData *d = 0; + QMap::iterator i = dataLoadings.find(reply); + if (i != dataLoadings.cend()) { + d = i.value(); + dataLoadings.erase(i); + + QJsonParseError e; + QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e); + if (e.error != QJsonParseError::NoError) { + DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link")); + return onFailed(reply); + } + failed(d); + + if (App::main()) App::main()->update(); + } else { + i = imageLoadings.find(reply); + if (i != imageLoadings.cend()) { + d = i.value(); + imageLoadings.erase(i); + + QPixmap thumb; + QByteArray format; + QByteArray data(reply->readAll()); + { + QBuffer buffer(&data); + QImageReader reader(&buffer); +#ifndef OS_MAC_OLD + reader.setAutoTransform(true); +#endif // OS_MAC_OLD + thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly); + format = reader.format(); + thumb.setDevicePixelRatio(cRetinaFactor()); + if (format.isEmpty()) format = QByteArray("JPG"); + } + d->loading = false; + d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format); + serverRedirects.remove(d); + if (App::main()) App::main()->update(); + } + } +} + +void LocationManager::onFailed(QNetworkReply *reply) { + if (!manager) return; + + LocationData *d = 0; + QMap::iterator i = dataLoadings.find(reply); + if (i != dataLoadings.cend()) { + d = i.value(); + dataLoadings.erase(i); + } else { + i = imageLoadings.find(reply); + if (i != imageLoadings.cend()) { + d = i.value(); + imageLoadings.erase(i); + } + } + DEBUG_LOG(("Network Error: failed to get data for image link %1,%2 error %3").arg(d ? d->coords.lat : 0).arg(d ? d->coords.lon : 0).arg(reply->errorString())); + if (d) { + failed(d); + } +} + +void LocationManager::failed(LocationData *data) { + data->loading = false; + data->thumb = *black; + serverRedirects.remove(data); +} + +void LocationData::load() { + if (!thumb->isNull()) return thumb->load(false, false); + if (loading) return; + + loading = true; + if (locationManager) { + locationManager->getData(this); + } +} diff --git a/Telegram/SourceFiles/history/history_location_manager.h b/Telegram/SourceFiles/history/history_location_manager.h new file mode 100644 index 0000000000..bf422e4bbf --- /dev/null +++ b/Telegram/SourceFiles/history/history_location_manager.h @@ -0,0 +1,120 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +void initLocationManager(); +void reinitLocationManager(); +void deinitLocationManager(); + +struct LocationCoords { + LocationCoords() : lat(0), lon(0) { + } + LocationCoords(float64 lat, float64 lon) : lat(lat), lon(lon) { + } + LocationCoords(const MTPDgeoPoint &point) : lat(point.vlat.v), lon(point.vlong.v) { + } + float64 lat, lon; +}; +inline bool operator==(const LocationCoords &a, const LocationCoords &b) { + return (a.lat == b.lat) && (a.lon == b.lon); +} +inline bool operator<(const LocationCoords &a, const LocationCoords &b) { + return (a.lat < b.lat) || ((a.lat == b.lat) && (a.lon < b.lon)); +} +inline uint qHash(const LocationCoords &t, uint seed = 0) { +#ifndef OS_MAC_OLD + return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed); +#else // OS_MAC_OLD + uint h1 = qHash(t.lat, seed); + uint h2 = qHash(t.lon, seed); + return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed; +#endif // OS_MAC_OLD +} + +struct LocationData { + LocationData(const LocationCoords &coords) : coords(coords), loading(false) { + } + + LocationCoords coords; + ImagePtr thumb; + bool loading; + + void load(); +}; + +class LocationClickHandler : public ClickHandler { +public: + LocationClickHandler(const LocationCoords &coords) : _coords(coords) { + setup(); + } + + void onClick(Qt::MouseButton button) const override; + + QString tooltip() const override { + return QString(); + } + + QString dragText() const override { + return _text; + } + + void copyToClipboard() const override { + if (!_text.isEmpty()) { + QApplication::clipboard()->setText(_text); + } + } + QString copyToClipboardContextItemText() const override; + +private: + + void setup(); + LocationCoords _coords; + QString _text; + +}; + +class LocationManager : public QObject { + Q_OBJECT + +public: + void init(); + void reinit(); + void deinit(); + + void getData(LocationData *data); + + ~LocationManager() { + deinit(); + } + +public slots: + void onFinished(QNetworkReply *reply); + void onFailed(QNetworkReply *reply); + +private: + void failed(LocationData *data); + + QNetworkAccessManager *manager = nullptr; + QMap dataLoadings, imageLoadings; + QMap serverRedirects; + ImagePtr *black = nullptr; + +}; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 198a634b1a..b4dc8eb68c 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -5797,16 +5797,13 @@ void HistoryWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button BotCallbackInfo info = { bot, msg->fullId(), row, col, (button->type == ButtonType::Game) }; MTPmessages_GetBotCallbackAnswer::Flags flags = 0; QByteArray sendData; - int32 sendGameId = 0; if (info.game) { - flags = MTPmessages_GetBotCallbackAnswer::Flag::f_game_id; - auto strData = QString::fromUtf8(button->data); - sendGameId = strData.midRef(0, strData.indexOf(',')).toInt(); + flags = MTPmessages_GetBotCallbackAnswer::Flag::f_game; } else if (button->type == ButtonType::Callback) { flags = MTPmessages_GetBotCallbackAnswer::Flag::f_data; sendData = button->data; } - button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData), MTP_int(sendGameId)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info)); + button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info)); Ui::repaintHistoryItem(msg); if (_replyToId == msg->id) { @@ -8138,7 +8135,7 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp _previewRequest = 0; } if (result.type() == mtpc_messageMediaWebPage) { - WebPageData *data = App::feedWebPage(result.c_messageMediaWebPage().vwebpage); + auto data = App::feedWebPage(result.c_messageMediaWebPage().vwebpage); _previewCache.insert(links, data->id); if (data->pendingTill > 0 && data->pendingTill <= unixtime()) { data->pendingTill = -1; @@ -8147,7 +8144,7 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp _previewData = (data->id && data->pendingTill >= 0) ? data : 0; updatePreview(); } - if (App::main()) App::main()->webPagesUpdate(); + if (App::main()) App::main()->webPagesOrGamesUpdate(); } else if (result.type() == mtpc_messageMediaEmpty) { _previewCache.insert(links, 0); if (links == _previewLinks && !_previewCancelled) { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 49a70a392d..63385e707f 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_overview.h" #include "inline_bots/inline_bot_result.h" #include "media/media_clip_reader.h" +#include "history/history_location_manager.h" #include "localstorage.h" #include "mainwidget.h" #include "lang.h" diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h index 031ee992e5..3c2e8fbf42 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/basic_types.h" #include "structs.h" #include "mtproto/core_types.h" +#include "history/history_location_manager.h" namespace InlineBots { @@ -62,7 +63,6 @@ public: // Only SendFile and SendPhoto work by their own. class SendDataCommon : public SendData { public: - struct SentMTPMessageFields { MTPString text = MTP_string(""); MTPVector entities = MTPnullEntities; @@ -99,7 +99,7 @@ private: // Message with geo location point media. class SendGeo : public SendDataCommon { public: - SendGeo(const MTPDgeoPoint &point) : _location(point) { + explicit SendGeo(const MTPDgeoPoint &point) : _location(point) { } bool isValid() const override { diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 28d1bece68..5027ec7dca 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -2978,11 +2978,11 @@ public: voice->waveform[0] = -2; voice->wavemax = 0; } - const DocumentItems &items(App::documentItems()); - DocumentItems::const_iterator i = items.constFind(_doc); + auto &items = App::documentItems(); + auto i = items.constFind(_doc); if (i != items.cend()) { - for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - Ui::repaintHistoryItem(j.key()); + for_const (auto item, i.value()) { + Ui::repaintHistoryItem(item); } } } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d96db84ee4..cb6b37fe99 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -102,8 +102,8 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window) connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted())); connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement())); - _webPageUpdater.setSingleShot(true); - connect(&_webPageUpdater, SIGNAL(timeout()), this, SLOT(webPagesUpdate())); + _webPageOrGameUpdater.setSingleShot(true); + connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate())); subscribe(Window::chatBackground(), [this](const Window::ChatBackgroundUpdate &update) { using Update = Window::ChatBackgroundUpdate; @@ -341,24 +341,41 @@ void MainWidget::finishForwarding(History *history, bool silent) { } void MainWidget::webPageUpdated(WebPageData *data) { - _webPagesUpdated.insert(data->id, true); - _webPageUpdater.start(0); + _webPagesUpdated.insert(data->id); + _webPageOrGameUpdater.start(0); } -void MainWidget::webPagesUpdate() { - if (_webPagesUpdated.isEmpty()) return; +void MainWidget::gameUpdated(GameData *data) { + _gamesUpdated.insert(data->id); + _webPageOrGameUpdater.start(0); +} - _webPageUpdater.stop(); - const WebPageItems &items(App::webPageItems()); - for (QMap::const_iterator i = _webPagesUpdated.cbegin(), e = _webPagesUpdated.cend(); i != e; ++i) { - WebPageItems::const_iterator j = items.constFind(App::webPage(i.key())); - if (j != items.cend()) { - for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) { - k.key()->setPendingInitDimensions(); +void MainWidget::webPagesOrGamesUpdate() { + _webPageOrGameUpdater.stop(); + if (!_webPagesUpdated.isEmpty()) { + auto &items = App::webPageItems(); + for_const (auto webPageId, _webPagesUpdated) { + auto j = items.constFind(App::webPage(webPageId)); + if (j != items.cend()) { + for_const (auto item, j.value()) { + item->setPendingInitDimensions(); + } } } + _webPagesUpdated.clear(); + } + if (!_gamesUpdated.isEmpty()) { + auto &items = App::gameItems(); + for_const (auto gameId, _gamesUpdated) { + auto j = items.constFind(App::game(gameId)); + if (j != items.cend()) { + for_const (auto item, j.value()) { + item->setPendingInitDimensions(); + } + } + } + _gamesUpdated.clear(); } - _webPagesUpdated.clear(); } void MainWidget::updateMutedIn(int32 seconds) { @@ -470,8 +487,8 @@ void MainWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) { const SharedContactItems &items(App::sharedContactItems()); SharedContactItems::const_iterator i = items.constFind(peerToUser(user->id)); if (i != items.cend()) { - for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - j.key()->setPendingInitDimensions(); + for_const (auto item, i.value()) { + item->setPendingInitDimensions(); } } @@ -1151,7 +1168,7 @@ void MainWidget::sendMessage(const MessageToSend &message) { if (message.webPageId == CancelledWebPageId) { sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage; } else if (message.webPageId) { - WebPageData *page = App::webPage(message.webPageId); + auto page = App::webPage(message.webPageId); media = MTP_messageMediaWebPage(MTP_webPagePending(MTP_long(page->id), MTP_int(page->pendingTill))); flags |= MTPDmessage::Flag::f_media; } @@ -1612,8 +1629,8 @@ void MainWidget::documentLoadProgress(FileLoader *loader) { const DocumentItems &items(App::documentItems()); DocumentItems::const_iterator i = items.constFind(document); if (i != items.cend()) { - for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - Ui::repaintHistoryItem(j.key()); + for_const (auto item, i.value()) { + Ui::repaintHistoryItem(item); } } App::wnd()->documentUpdated(document); @@ -1674,11 +1691,11 @@ void MainWidget::mediaMarkRead(DocumentData *data) { void MainWidget::mediaMarkRead(const HistoryItemsMap &items) { QVector markedIds; markedIds.reserve(items.size()); - for (HistoryItemsMap::const_iterator j = items.cbegin(), e = items.cend(); j != e; ++j) { - if (!j.key()->out() && j.key()->isMediaUnread()) { - j.key()->markMediaRead(); - if (j.key()->id > 0) { - markedIds.push_back(MTP_int(j.key()->id)); + for_const (auto item, items) { + if (!item->out() && item->isMediaUnread()) { + item->markMediaRead(); + if (item->id > 0) { + markedIds.push_back(MTP_int(item->id)); } } } @@ -4179,8 +4196,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } if (needToAdd) { - HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); - if (item) { + if (auto item = App::histories().addNewMessage(d.vmessage, NewMessageUnread)) { _history->peerMessagesUpdated(item->history()->peer->id); } } @@ -4188,11 +4204,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateMessageID: { - const auto &d(update.c_updateMessageID()); - FullMsgId msg = App::histItemByRandom(d.vrandom_id.v); + auto &d = update.c_updateMessageID(); + auto msg = App::histItemByRandom(d.vrandom_id.v); if (msg.msg) { - HistoryItem *msgRow = App::histItemById(msg); - if (msgRow) { + if (auto msgRow = App::histItemById(msg)) { if (App::histItemById(msg.channel, d.vid.v)) { History *h = msgRow->history(); bool wasLast = (h->lastMsg == msgRow); @@ -4218,14 +4233,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadMessagesContents: { - const auto &d(update.c_updateReadMessagesContents()); + auto &d = update.c_updateReadMessagesContents(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } // update before applying skipped - const auto &v(d.vmessages.c_vector().v); + auto &v = d.vmessages.c_vector().v; for (int32 i = 0, l = v.size(); i < l; ++i) { if (HistoryItem *item = App::histItemById(NoChannel, v.at(i).v)) { if (item->isMediaUnread()) { @@ -4244,7 +4259,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadHistoryInbox: { - const auto &d(update.c_updateReadHistoryInbox()); + auto &d = update.c_updateReadHistoryInbox(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; @@ -4257,7 +4272,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadHistoryOutbox: { - const auto &d(update.c_updateReadHistoryOutbox()); + auto &d = update.c_updateReadHistoryOutbox(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; @@ -4275,7 +4290,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateWebPage: { - const auto &d(update.c_updateWebPage()); + auto &d = update.c_updateWebPage(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; @@ -4284,13 +4299,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped App::feedWebPage(d.vwebpage); _history->updatePreview(); - webPagesUpdate(); + webPagesOrGamesUpdate(); ptsApplySkippedUpdates(); } break; case mtpc_updateDeleteMessages: { - const auto &d(update.c_updateDeleteMessages()); + auto &d = update.c_updateDeleteMessages(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; @@ -4304,9 +4319,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserTyping: { - const auto &d(update.c_updateUserTyping()); - History *history = App::historyLoaded(peerFromUser(d.vuser_id)); - UserData *user = App::userLoaded(d.vuser_id.v); + auto &d = update.c_updateUserTyping(); + auto history = App::historyLoaded(peerFromUser(d.vuser_id)); + auto user = App::userLoaded(d.vuser_id.v); if (history && user) { auto when = requestingDifference() ? 0 : unixtime(); App::histories().regSendAction(history, user, d.vaction, when); @@ -4314,14 +4329,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateChatUserTyping: { - const auto &d(update.c_updateChatUserTyping()); + auto &d = update.c_updateChatUserTyping(); History *history = 0; - if (PeerData *chat = App::chatLoaded(d.vchat_id.v)) { + if (auto chat = App::chatLoaded(d.vchat_id.v)) { history = App::historyLoaded(chat->id); - } else if (PeerData *channel = App::channelLoaded(d.vchat_id.v)) { + } else if (auto channel = App::channelLoaded(d.vchat_id.v)) { history = App::historyLoaded(channel->id); } - UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v); + auto user = (d.vuser_id.v == MTP::authedId()) ? nullptr : App::userLoaded(d.vuser_id.v); if (history && user) { auto when = requestingDifference() ? 0 : unixtime(); App::histories().regSendAction(history, user, d.vaction, when); @@ -4349,9 +4364,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserStatus: { - const auto &d(update.c_updateUserStatus()); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { + auto &d = update.c_updateUserStatus(); + if (auto user = App::userLoaded(d.vuser_id.v)) { switch (d.vstatus.type()) { case mtpc_userStatusEmpty: user->onlineTill = 0; break; case mtpc_userStatusRecently: @@ -4380,7 +4394,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserName: { - auto &d(update.c_updateUserName()); + auto &d = update.c_updateUserName(); if (auto user = App::userLoaded(d.vuser_id.v)) { if (user->contact <= 0) { user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername))); @@ -4392,9 +4406,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserPhoto: { - const auto &d(update.c_updateUserPhoto()); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { + auto &d = update.c_updateUserPhoto(); + if (auto user = App::userLoaded(d.vuser_id.v)) { user->setPhoto(d.vphoto); user->loadUserpic(); if (mtpIsTrue(d.vprevious)) { @@ -4415,9 +4428,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateContactRegistered: { - const auto &d(update.c_updateContactRegistered()); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { + auto &d = update.c_updateContactRegistered(); + if (auto user = App::userLoaded(d.vuser_id.v)) { if (App::history(user->id)->loadedAtBottom()) { App::history(user->id)->addNewService(clientMsgId(), date(d.vdate), lng_action_user_registered(lt_from, user->name), 0); } @@ -4425,22 +4437,22 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateContactLink: { - const auto &d(update.c_updateContactLink()); + auto &d = update.c_updateContactLink(); App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link); } break; case mtpc_updateNotifySettings: { - const auto &d(update.c_updateNotifySettings()); + auto &d = update.c_updateNotifySettings(); applyNotifySetting(d.vpeer, d.vnotify_settings); } break; case mtpc_updateDcOptions: { - const auto &d(update.c_updateDcOptions()); + auto &d = update.c_updateDcOptions(); MTP::updateDcOptions(d.vdc_options.c_vector().v); } break; case mtpc_updateUserPhone: { - auto &d(update.c_updateUserPhone()); + auto &d = update.c_updateUserPhone(); if (auto user = App::userLoaded(d.vuser_id.v)) { auto newPhone = qs(d.vphone); if (newPhone != user->phone()) { @@ -4454,31 +4466,31 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateNewEncryptedMessage: { - const auto &d(update.c_updateNewEncryptedMessage()); + auto &d = update.c_updateNewEncryptedMessage(); } break; case mtpc_updateEncryptedChatTyping: { - const auto &d(update.c_updateEncryptedChatTyping()); + auto &d = update.c_updateEncryptedChatTyping(); } break; case mtpc_updateEncryption: { - const auto &d(update.c_updateEncryption()); + auto &d = update.c_updateEncryption(); } break; case mtpc_updateEncryptedMessagesRead: { - const auto &d(update.c_updateEncryptedMessagesRead()); + auto &d = update.c_updateEncryptedMessagesRead(); } break; case mtpc_updateUserBlocked: { - const auto &d(update.c_updateUserBlocked()); - if (UserData *user = App::userLoaded(d.vuser_id.v)) { + auto &d = update.c_updateUserBlocked(); + if (auto user = App::userLoaded(d.vuser_id.v)) { user->setBlockStatus(mtpIsTrue(d.vblocked) ? UserData::BlockStatus::Blocked : UserData::BlockStatus::NotBlocked); App::markPeerUpdated(user); } } break; case mtpc_updateNewAuthorization: { - const auto &d(update.c_updateNewAuthorization()); + auto &d = update.c_updateNewAuthorization(); QDateTime datetime = date(d.vdate); QString name = App::self()->firstName; @@ -4491,7 +4503,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateServiceNotification: { - const auto &d(update.c_updateServiceNotification()); + auto &d = update.c_updateServiceNotification(); if (mtpIsTrue(d.vpopup)) { Ui::showLayer(new InformBox(qs(d.vmessage))); } else { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 9394949670..84fb263800 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -344,6 +344,7 @@ public: void mediaMarkRead(const HistoryItemsMap &items); void webPageUpdated(WebPageData *page); + void gameUpdated(GameData *game); void updateMutedIn(int32 seconds); void updateStickers(); @@ -407,7 +408,6 @@ public: ~MainWidget(); signals: - void peerUpdated(PeerData *peer); void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); void peerPhotoChanged(PeerData *peer); @@ -417,8 +417,7 @@ signals: void savedGifsUpdated(); public slots: - - void webPagesUpdate(); + void webPagesOrGamesUpdate(); void audioPlayProgress(const AudioMsgId &audioId); void documentLoadProgress(FileLoader *loader); @@ -511,8 +510,9 @@ private: Text _toForwardFrom, _toForwardText; int32 _toForwardNameVersion = 0; - QMap _webPagesUpdated; - QTimer _webPageUpdater; + OrderedSet _webPagesUpdated; + OrderedSet _gamesUpdated; + QTimer _webPageOrGameUpdater; SingleTimer _updateMutedTimer; diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index ba2100cb35..286280dd9d 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -157,6 +157,7 @@ inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string pro inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia; inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia; +inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto; @@ -236,6 +237,7 @@ messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; +messageMediaGame#fdb19008 game:Game = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; @@ -250,7 +252,7 @@ messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#3a14cfa5 game_id:int score:int = MessageAction; +messageActionGameScore#92a72876 game_id:long score:int = MessageAction; dialog#66ffba14 flags:# peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; @@ -387,9 +389,9 @@ updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; updateChannelPinnedMessage#98592475 channel_id:int id:int = Update; -updateBotCallbackQuery#4bf9a8a0 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_id:flags.1?int = Update; +updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#4f2f45d1 flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_id:flags.1?int = Update; +updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update; updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; @@ -572,7 +574,7 @@ keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton; keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; -keyboardButtonGame#28fc3164 text:string game_title:string game_id:int start_param:string = KeyboardButton; +keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; @@ -647,10 +649,12 @@ inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:strin inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; +inputBotInlineMessageGame#3c00f8aa reply_markup:ReplyMarkup = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; +inputBotInlineResultGame#efff34f9 flags:# id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; @@ -721,6 +725,15 @@ maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; +game#b351c590 flags:# id:long access_hash:long short_name:string title:string description:string url:string photo:Photo document:flags.0?Document = Game; + +inputGameID#32c3e77 id:long access_hash:long = InputGame; +inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; + +highScore#58fffcd0 pos:int user_id:int score:int = HighScore; + +messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -851,7 +864,7 @@ messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:fla messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#6c996518 flags:# peer:InputPeer msg_id:int data:flags.0?bytes game_id:flags.1?int = messages.BotCallbackAnswer; +messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#c927d44b flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string = Bool; messages.getPeerDialogs#2d9776b9 peers:Vector = messages.PeerDialogs; messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector = Bool; @@ -862,10 +875,12 @@ messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = mes messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; -messages.setGameScore#dfbc7c1f flags:# edit_message:flags.0?true peer:InputPeer id:int user_id:InputUser game_id:int score:int = Updates; -messages.setInlineGameScore#54f882f1 flags:# edit_message:flags.0?true id:InputBotInlineMessageID user_id:InputUser game_id:int score:int = Bool; messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; +messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true peer:InputPeer id:int user_id:InputUser score:int = Updates; +messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; +messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; +messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; @@ -917,4 +932,4 @@ channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates; channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats; -// LAYER 56 +// LAYER 57 diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp index 58618e4b8b..a716a5f309 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp +++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp @@ -761,6 +761,19 @@ void _serialize_inputMediaDocumentExternal(MTPStringLogger &to, int32 stage, int } } +void _serialize_inputMediaGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ inputMediaGame"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_inputChatPhotoEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ inputChatPhotoEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -1528,6 +1541,19 @@ void _serialize_messageMediaVenue(MTPStringLogger &to, int32 stage, int32 lev, T } } +void _serialize_messageMediaGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messageMediaGame"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" game: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_messageActionEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ messageActionEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -1671,7 +1697,7 @@ void _serialize_messageActionGameScore(MTPStringLogger &to, int32 stage, int32 l to.add("\n").addSpaces(lev); } switch (stage) { - case 0: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 0: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 1: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } @@ -2999,7 +3025,7 @@ void _serialize_updateBotCallbackQuery(MTPStringLogger &to, int32 stage, int32 l case 4: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 5: to.add(" chat_instance: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 6: to.add(" data: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 7: to.add(" game_id: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 7: to.add(" game_short_name: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_game_short_name) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -3035,7 +3061,7 @@ void _serialize_updateInlineBotCallbackQuery(MTPStringLogger &to, int32 stage, i case 3: to.add(" msg_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 4: to.add(" chat_instance: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 5: to.add(" data: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 6: to.add(" game_id: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 6: to.add(" game_short_name: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_game_short_name) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -4627,9 +4653,6 @@ void _serialize_keyboardButtonGame(MTPStringLogger &to, int32 stage, int32 lev, } switch (stage) { case 0: to.add(" text: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" game_title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 2: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 3: to.add(" start_param: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -5363,6 +5386,19 @@ void _serialize_inputBotInlineMessageMediaContact(MTPStringLogger &to, int32 sta } } +void _serialize_inputBotInlineMessageGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ inputBotInlineMessageGame"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" reply_markup: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_inputBotInlineResult(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { MTPDinputBotInlineResult::Flags flag(iflag); @@ -5427,6 +5463,22 @@ void _serialize_inputBotInlineResultDocument(MTPStringLogger &to, int32 stage, i } } +void _serialize_inputBotInlineResultGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ inputBotInlineResultGame"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" send_message: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_botInlineMessageMediaAuto(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { MTPDbotInlineMessageMediaAuto::Flags flag(iflag); @@ -5996,6 +6048,86 @@ void _serialize_inputStickeredMediaDocument(MTPStringLogger &to, int32 stage, in } } +void _serialize_game(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + MTPDgame::Flags flag(iflag); + + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ game"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 4: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 5: to.add(" description: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 6: to.add(" url: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 7: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 8: to.add(" document: "); ++stages.back(); if (flag & MTPDgame::Flag::f_document) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_inputGameID(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ inputGameID"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_inputGameShortName(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ inputGameShortName"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" bot_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_highScore(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ highScore"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" pos: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_messages_highScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_highScores"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" scores: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" users: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { if (stage) { to.add(",\n").addSpaces(lev); @@ -6691,8 +6823,7 @@ void _serialize_messages_setInlineGameScore(MTPStringLogger &to, int32 stage, in case 1: to.add(" edit_message: "); ++stages.back(); if (flag & MTPmessages_setInlineGameScore::Flag::f_edit_message) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; case 2: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 3: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 4: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 5: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 4: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -7828,8 +7959,7 @@ void _serialize_messages_setGameScore(MTPStringLogger &to, int32 stage, int32 le case 2: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 3: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 4: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 5: to.add(" game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 6: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 5: to.add(" score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -8387,10 +8517,10 @@ void _serialize_messages_getBotCallbackAnswer(MTPStringLogger &to, int32 stage, } switch (stage) { case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 2: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 3: to.add(" data: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; - case 4: to.add(" game_id: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 1: to.add(" game: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_game) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break; + case 2: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 4: to.add(" data: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -8469,6 +8599,35 @@ void _serialize_messages_getAttachedStickers(MTPStringLogger &to, int32 stage, i } } +void _serialize_messages_getGameHighScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getGameHighScores"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + +void _serialize_messages_getInlineGameHighScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_getInlineGameHighScores"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } +} + void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) { to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -8739,6 +8898,7 @@ namespace { _serializers.insert(mtpc_inputMediaGifExternal, _serialize_inputMediaGifExternal); _serializers.insert(mtpc_inputMediaPhotoExternal, _serialize_inputMediaPhotoExternal); _serializers.insert(mtpc_inputMediaDocumentExternal, _serialize_inputMediaDocumentExternal); + _serializers.insert(mtpc_inputMediaGame, _serialize_inputMediaGame); _serializers.insert(mtpc_inputChatPhotoEmpty, _serialize_inputChatPhotoEmpty); _serializers.insert(mtpc_inputChatUploadedPhoto, _serialize_inputChatUploadedPhoto); _serializers.insert(mtpc_inputChatPhoto, _serialize_inputChatPhoto); @@ -8800,6 +8960,7 @@ namespace { _serializers.insert(mtpc_messageMediaDocument, _serialize_messageMediaDocument); _serializers.insert(mtpc_messageMediaWebPage, _serialize_messageMediaWebPage); _serializers.insert(mtpc_messageMediaVenue, _serialize_messageMediaVenue); + _serializers.insert(mtpc_messageMediaGame, _serialize_messageMediaGame); _serializers.insert(mtpc_messageActionEmpty, _serialize_messageActionEmpty); _serializers.insert(mtpc_messageActionChatCreate, _serialize_messageActionChatCreate); _serializers.insert(mtpc_messageActionChatEditTitle, _serialize_messageActionChatEditTitle); @@ -9106,9 +9267,11 @@ namespace { _serializers.insert(mtpc_inputBotInlineMessageMediaGeo, _serialize_inputBotInlineMessageMediaGeo); _serializers.insert(mtpc_inputBotInlineMessageMediaVenue, _serialize_inputBotInlineMessageMediaVenue); _serializers.insert(mtpc_inputBotInlineMessageMediaContact, _serialize_inputBotInlineMessageMediaContact); + _serializers.insert(mtpc_inputBotInlineMessageGame, _serialize_inputBotInlineMessageGame); _serializers.insert(mtpc_inputBotInlineResult, _serialize_inputBotInlineResult); _serializers.insert(mtpc_inputBotInlineResultPhoto, _serialize_inputBotInlineResultPhoto); _serializers.insert(mtpc_inputBotInlineResultDocument, _serialize_inputBotInlineResultDocument); + _serializers.insert(mtpc_inputBotInlineResultGame, _serialize_inputBotInlineResultGame); _serializers.insert(mtpc_botInlineMessageMediaAuto, _serialize_botInlineMessageMediaAuto); _serializers.insert(mtpc_botInlineMessageText, _serialize_botInlineMessageText); _serializers.insert(mtpc_botInlineMessageMediaGeo, _serialize_botInlineMessageMediaGeo); @@ -9154,6 +9317,11 @@ namespace { _serializers.insert(mtpc_maskCoords, _serialize_maskCoords); _serializers.insert(mtpc_inputStickeredMediaPhoto, _serialize_inputStickeredMediaPhoto); _serializers.insert(mtpc_inputStickeredMediaDocument, _serialize_inputStickeredMediaDocument); + _serializers.insert(mtpc_game, _serialize_game); + _serializers.insert(mtpc_inputGameID, _serialize_inputGameID); + _serializers.insert(mtpc_inputGameShortName, _serialize_inputGameShortName); + _serializers.insert(mtpc_highScore, _serialize_highScore); + _serializers.insert(mtpc_messages_highScores, _serialize_messages_highScores); _serializers.insert(mtpc_req_pq, _serialize_req_pq); _serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params); @@ -9330,6 +9498,8 @@ namespace { _serializers.insert(mtpc_messages_getRecentStickers, _serialize_messages_getRecentStickers); _serializers.insert(mtpc_messages_getArchivedStickers, _serialize_messages_getArchivedStickers); _serializers.insert(mtpc_messages_getAttachedStickers, _serialize_messages_getAttachedStickers); + _serializers.insert(mtpc_messages_getGameHighScores, _serialize_messages_getGameHighScores); + _serializers.insert(mtpc_messages_getInlineGameHighScores, _serialize_messages_getInlineGameHighScores); _serializers.insert(mtpc_updates_getState, _serialize_updates_getState); _serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference); _serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference); diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 9f9813388a..5767a2ad8c 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -30,7 +30,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org namespace MTP { namespace internal { -static constexpr mtpPrime CurrentLayer = 56; +static constexpr mtpPrime CurrentLayer = 57; class TypeCreator; @@ -105,6 +105,7 @@ enum { mtpc_inputMediaGifExternal = 0x4843b0fd, mtpc_inputMediaPhotoExternal = 0xb55f4f18, mtpc_inputMediaDocumentExternal = 0xe5e9607c, + mtpc_inputMediaGame = 0xd33f43f3, mtpc_inputChatPhotoEmpty = 0x1ca48f57, mtpc_inputChatUploadedPhoto = 0x927c55b4, mtpc_inputChatPhoto = 0x8953ad37, @@ -166,6 +167,7 @@ enum { mtpc_messageMediaDocument = 0xf3e02ea8, mtpc_messageMediaWebPage = 0xa32dd600, mtpc_messageMediaVenue = 0x7912b71f, + mtpc_messageMediaGame = 0xfdb19008, mtpc_messageActionEmpty = 0xb6aef7b0, mtpc_messageActionChatCreate = 0xa6638b9a, mtpc_messageActionChatEditTitle = 0xb5a1ce5a, @@ -179,7 +181,7 @@ enum { mtpc_messageActionChannelMigrateFrom = 0xb055eaee, mtpc_messageActionPinMessage = 0x94bd38ed, mtpc_messageActionHistoryClear = 0x9fbab604, - mtpc_messageActionGameScore = 0x3a14cfa5, + mtpc_messageActionGameScore = 0x92a72876, mtpc_dialog = 0x66ffba14, mtpc_photoEmpty = 0x2331b22d, mtpc_photo = 0x9288dd29, @@ -284,9 +286,9 @@ enum { mtpc_updateBotInlineSend = 0xe48f964, mtpc_updateEditChannelMessage = 0x1b3f4df7, mtpc_updateChannelPinnedMessage = 0x98592475, - mtpc_updateBotCallbackQuery = 0x4bf9a8a0, + mtpc_updateBotCallbackQuery = 0xe73547e1, mtpc_updateEditMessage = 0xe40370a3, - mtpc_updateInlineBotCallbackQuery = 0x4f2f45d1, + mtpc_updateInlineBotCallbackQuery = 0xf9d27a5a, mtpc_updateReadChannelOutbox = 0x25d6c9c7, mtpc_updateDraftMessage = 0xee2bb969, mtpc_updateReadFeaturedStickers = 0x571d2742, @@ -416,7 +418,7 @@ enum { mtpc_keyboardButtonRequestPhone = 0xb16a6c29, mtpc_keyboardButtonRequestGeoLocation = 0xfc796b3f, mtpc_keyboardButtonSwitchInline = 0x568a748, - mtpc_keyboardButtonGame = 0x28fc3164, + mtpc_keyboardButtonGame = 0x50f41ccf, mtpc_keyboardButtonRow = 0x77608b83, mtpc_replyKeyboardHide = 0xa03e5b85, mtpc_replyKeyboardForceReply = 0xf4108aa0, @@ -472,9 +474,11 @@ enum { mtpc_inputBotInlineMessageMediaGeo = 0xf4a59de1, mtpc_inputBotInlineMessageMediaVenue = 0xaaafadc8, mtpc_inputBotInlineMessageMediaContact = 0x2daf01a7, + mtpc_inputBotInlineMessageGame = 0x3c00f8aa, mtpc_inputBotInlineResult = 0x2cbbe15a, mtpc_inputBotInlineResultPhoto = 0xa8d864a7, mtpc_inputBotInlineResultDocument = 0xfff8fdc4, + mtpc_inputBotInlineResultGame = 0xefff34f9, mtpc_botInlineMessageMediaAuto = 0xa74b15b, mtpc_botInlineMessageText = 0x8c7f65e2, mtpc_botInlineMessageMediaGeo = 0x3a8fd8b8, @@ -520,6 +524,11 @@ enum { mtpc_maskCoords = 0xaed6dbb2, mtpc_inputStickeredMediaPhoto = 0x4a992157, mtpc_inputStickeredMediaDocument = 0x438865b, + mtpc_game = 0xb351c590, + mtpc_inputGameID = 0x32c3e77, + mtpc_inputGameShortName = 0xc331e80a, + mtpc_highScore = 0x58fffcd0, + mtpc_messages_highScores = 0x9a3bfd99, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_initConnection = 0x69796de9, @@ -643,7 +652,7 @@ enum { mtpc_messages_getMessageEditData = 0xfda68d36, mtpc_messages_editMessage = 0xce91e4ca, mtpc_messages_editInlineBotMessage = 0x130c2c85, - mtpc_messages_getBotCallbackAnswer = 0x6c996518, + mtpc_messages_getBotCallbackAnswer = 0x810a9fec, mtpc_messages_setBotCallbackAnswer = 0xc927d44b, mtpc_messages_getPeerDialogs = 0x2d9776b9, mtpc_messages_saveDraft = 0xbc39e14b, @@ -654,10 +663,12 @@ enum { mtpc_messages_saveRecentSticker = 0x392718f8, mtpc_messages_clearRecentStickers = 0x8999602d, mtpc_messages_getArchivedStickers = 0x57f17692, - mtpc_messages_setGameScore = 0xdfbc7c1f, - mtpc_messages_setInlineGameScore = 0x54f882f1, mtpc_messages_getMaskStickers = 0x65b8c79f, mtpc_messages_getAttachedStickers = 0xcc5b67cc, + mtpc_messages_setGameScore = 0x8ef8ecc0, + mtpc_messages_setInlineGameScore = 0x15ad9f64, + mtpc_messages_getGameHighScores = 0xe822649d, + mtpc_messages_getInlineGameHighScores = 0xf635e1b, mtpc_updates_getState = 0xedd4882a, mtpc_updates_getDifference = 0xa041495, mtpc_updates_getChannelDifference = 0xbb32d7c0, @@ -811,6 +822,7 @@ class MTPDinputMediaVenue; class MTPDinputMediaGifExternal; class MTPDinputMediaPhotoExternal; class MTPDinputMediaDocumentExternal; +class MTPDinputMediaGame; class MTPinputChatPhoto; class MTPDinputChatUploadedPhoto; @@ -887,6 +899,7 @@ class MTPDmessageMediaContact; class MTPDmessageMediaDocument; class MTPDmessageMediaWebPage; class MTPDmessageMediaVenue; +class MTPDmessageMediaGame; class MTPmessageAction; class MTPDmessageActionChatCreate; @@ -1322,11 +1335,13 @@ class MTPDinputBotInlineMessageText; class MTPDinputBotInlineMessageMediaGeo; class MTPDinputBotInlineMessageMediaVenue; class MTPDinputBotInlineMessageMediaContact; +class MTPDinputBotInlineMessageGame; class MTPinputBotInlineResult; class MTPDinputBotInlineResult; class MTPDinputBotInlineResultPhoto; class MTPDinputBotInlineResultDocument; +class MTPDinputBotInlineResultGame; class MTPbotInlineMessage; class MTPDbotInlineMessageMediaAuto; @@ -1408,6 +1423,19 @@ class MTPinputStickeredMedia; class MTPDinputStickeredMediaPhoto; class MTPDinputStickeredMediaDocument; +class MTPgame; +class MTPDgame; + +class MTPinputGame; +class MTPDinputGameID; +class MTPDinputGameShortName; + +class MTPhighScore; +class MTPDhighScore; + +class MTPmessages_highScores; +class MTPDmessages_highScores; + // Boxed types definitions typedef MTPBoxed MTPResPQ; @@ -1588,6 +1616,10 @@ typedef MTPBoxed MTPmessages_StickerSetInst typedef MTPBoxed MTPStickerSetCovered; typedef MTPBoxed MTPMaskCoords; typedef MTPBoxed MTPInputStickeredMedia; +typedef MTPBoxed MTPGame; +typedef MTPBoxed MTPInputGame; +typedef MTPBoxed MTPHighScore; +typedef MTPBoxed MTPmessages_HighScores; // Type classes definitions @@ -2774,6 +2806,18 @@ public: return *(const MTPDinputMediaDocumentExternal*)data; } + MTPDinputMediaGame &_inputMediaGame() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGame); + split(); + return *(MTPDinputMediaGame*)data; + } + const MTPDinputMediaGame &c_inputMediaGame() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGame); + return *(const MTPDinputMediaGame*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -2794,6 +2838,7 @@ private: explicit MTPinputMedia(MTPDinputMediaGifExternal *_data); explicit MTPinputMedia(MTPDinputMediaPhotoExternal *_data); explicit MTPinputMedia(MTPDinputMediaDocumentExternal *_data); + explicit MTPinputMedia(MTPDinputMediaGame *_data); friend class MTP::internal::TypeCreator; @@ -3725,6 +3770,18 @@ public: return *(const MTPDmessageMediaVenue*)data; } + MTPDmessageMediaGame &_messageMediaGame() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGame); + split(); + return *(MTPDmessageMediaGame*)data; + } + const MTPDmessageMediaGame &c_messageMediaGame() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGame); + return *(const MTPDmessageMediaGame*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -3740,6 +3797,7 @@ private: explicit MTPmessageMedia(MTPDmessageMediaDocument *_data); explicit MTPmessageMedia(MTPDmessageMediaWebPage *_data); explicit MTPmessageMedia(MTPDmessageMediaVenue *_data); + explicit MTPmessageMedia(MTPDmessageMediaGame *_data); friend class MTP::internal::TypeCreator; @@ -8877,6 +8935,18 @@ public: return *(const MTPDinputBotInlineMessageMediaContact*)data; } + MTPDinputBotInlineMessageGame &_inputBotInlineMessageGame() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputBotInlineMessageGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineMessageGame); + split(); + return *(MTPDinputBotInlineMessageGame*)data; + } + const MTPDinputBotInlineMessageGame &c_inputBotInlineMessageGame() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputBotInlineMessageGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineMessageGame); + return *(const MTPDinputBotInlineMessageGame*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -8891,6 +8961,7 @@ private: explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaGeo *_data); explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaVenue *_data); explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaContact *_data); + explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageGame *_data); friend class MTP::internal::TypeCreator; @@ -8942,6 +9013,18 @@ public: return *(const MTPDinputBotInlineResultDocument*)data; } + MTPDinputBotInlineResultGame &_inputBotInlineResultGame() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputBotInlineResultGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineResultGame); + split(); + return *(MTPDinputBotInlineResultGame*)data; + } + const MTPDinputBotInlineResultGame &c_inputBotInlineResultGame() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputBotInlineResultGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineResultGame); + return *(const MTPDinputBotInlineResultGame*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -8954,6 +9037,7 @@ private: explicit MTPinputBotInlineResult(MTPDinputBotInlineResult *_data); explicit MTPinputBotInlineResult(MTPDinputBotInlineResultPhoto *_data); explicit MTPinputBotInlineResult(MTPDinputBotInlineResultDocument *_data); + explicit MTPinputBotInlineResult(MTPDinputBotInlineResultGame *_data); friend class MTP::internal::TypeCreator; @@ -9881,6 +9965,149 @@ private: }; typedef MTPBoxed MTPInputStickeredMedia; +class MTPgame : private mtpDataOwner { +public: + MTPgame(); + MTPgame(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_game) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDgame &_game() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDgame*)data; + } + const MTPDgame &c_game() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDgame*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_game); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPgame(MTPDgame *_data); + + friend class MTP::internal::TypeCreator; +}; +typedef MTPBoxed MTPGame; + +class MTPinputGame : private mtpDataOwner { +public: + MTPinputGame() : mtpDataOwner(0), _type(0) { + } + MTPinputGame(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { + read(from, end, cons); + } + + MTPDinputGameID &_inputGameID() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGameID) throw mtpErrorWrongTypeId(_type, mtpc_inputGameID); + split(); + return *(MTPDinputGameID*)data; + } + const MTPDinputGameID &c_inputGameID() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGameID) throw mtpErrorWrongTypeId(_type, mtpc_inputGameID); + return *(const MTPDinputGameID*)data; + } + + MTPDinputGameShortName &_inputGameShortName() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGameShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputGameShortName); + split(); + return *(MTPDinputGameShortName*)data; + } + const MTPDinputGameShortName &c_inputGameShortName() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_inputGameShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputGameShortName); + return *(const MTPDinputGameShortName*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPinputGame(mtpTypeId type); + explicit MTPinputGame(MTPDinputGameID *_data); + explicit MTPinputGame(MTPDinputGameShortName *_data); + + friend class MTP::internal::TypeCreator; + + mtpTypeId _type; +}; +typedef MTPBoxed MTPInputGame; + +class MTPhighScore : private mtpDataOwner { +public: + MTPhighScore(); + MTPhighScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_highScore) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDhighScore &_highScore() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDhighScore*)data; + } + const MTPDhighScore &c_highScore() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDhighScore*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_highScore); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPhighScore(MTPDhighScore *_data); + + friend class MTP::internal::TypeCreator; +}; +typedef MTPBoxed MTPHighScore; + +class MTPmessages_highScores : private mtpDataOwner { +public: + MTPmessages_highScores(); + MTPmessages_highScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_highScores) : mtpDataOwner(0) { + read(from, end, cons); + } + + MTPDmessages_highScores &_messages_highScores() { + if (!data) throw mtpErrorUninitialized(); + split(); + return *(MTPDmessages_highScores*)data; + } + const MTPDmessages_highScores &c_messages_highScores() const { + if (!data) throw mtpErrorUninitialized(); + return *(const MTPDmessages_highScores*)data; + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_highScores); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPmessages_highScores(MTPDmessages_highScores *_data); + + friend class MTP::internal::TypeCreator; +}; +typedef MTPBoxed MTPmessages_HighScores; + // Type constructors with data class MTPDresPQ : public mtpDataImpl { @@ -10457,6 +10684,16 @@ public: MTPstring vcaption; }; +class MTPDinputMediaGame : public mtpDataImpl { +public: + MTPDinputMediaGame() { + } + MTPDinputMediaGame(const MTPInputGame &_id) : vid(_id) { + } + + MTPInputGame vid; +}; + class MTPDinputChatUploadedPhoto : public mtpDataImpl { public: MTPDinputChatUploadedPhoto() { @@ -11174,6 +11411,16 @@ public: MTPstring vvenue_id; }; +class MTPDmessageMediaGame : public mtpDataImpl { +public: + MTPDmessageMediaGame() { + } + MTPDmessageMediaGame(const MTPGame &_game) : vgame(_game) { + } + + MTPGame vgame; +}; + class MTPDmessageActionChatCreate : public mtpDataImpl { public: MTPDmessageActionChatCreate() { @@ -11270,10 +11517,10 @@ class MTPDmessageActionGameScore : public mtpDataImpl(v)); } bool has_data() const { return vflags.v & Flag::f_data; } - bool has_game_id() const { return vflags.v & Flag::f_game_id; } + bool has_game_short_name() const { return vflags.v & Flag::f_game_short_name; } MTPDupdateBotCallbackQuery() { } - MTPDupdateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vpeer(_peer), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_id(_game_id) { + MTPDupdateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vpeer(_peer), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_short_name(_game_short_name) { } MTPflags vflags; @@ -12375,7 +12622,7 @@ public: MTPint vmsg_id; MTPlong vchat_instance; MTPbytes vdata; - MTPint vgame_id; + MTPstring vgame_short_name; }; class MTPDupdateEditMessage : public mtpDataImpl { @@ -12394,7 +12641,7 @@ class MTPDupdateInlineBotCallbackQuery : public mtpDataImpl(v)); } bool has_data() const { return vflags.v & Flag::f_data; } - bool has_game_id() const { return vflags.v & Flag::f_game_id; } + bool has_game_short_name() const { return vflags.v & Flag::f_game_short_name; } MTPDupdateInlineBotCallbackQuery() { } - MTPDupdateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_id(_game_id) { + MTPDupdateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_short_name(_game_short_name) { } MTPflags vflags; @@ -12415,7 +12662,7 @@ public: MTPInputBotInlineMessageID vmsg_id; MTPlong vchat_instance; MTPbytes vdata; - MTPint vgame_id; + MTPstring vgame_short_name; }; class MTPDupdateReadChannelOutbox : public mtpDataImpl { @@ -13730,13 +13977,10 @@ class MTPDkeyboardButtonGame : public mtpDataImpl { public: MTPDkeyboardButtonGame() { } - MTPDkeyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) : vtext(_text), vgame_title(_game_title), vgame_id(_game_id), vstart_param(_start_param) { + MTPDkeyboardButtonGame(const MTPstring &_text) : vtext(_text) { } MTPstring vtext; - MTPstring vgame_title; - MTPint vgame_id; - MTPstring vstart_param; }; class MTPDkeyboardButtonRow : public mtpDataImpl { @@ -14393,6 +14637,16 @@ public: MTPReplyMarkup vreply_markup; }; +class MTPDinputBotInlineMessageGame : public mtpDataImpl { +public: + MTPDinputBotInlineMessageGame() { + } + MTPDinputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) : vreply_markup(_reply_markup) { + } + + MTPReplyMarkup vreply_markup; +}; + class MTPDinputBotInlineResult : public mtpDataImpl { public: enum class Flag : int32 { @@ -14482,6 +14736,25 @@ public: MTPInputBotInlineMessage vsend_message; }; +class MTPDinputBotInlineResultGame : public mtpDataImpl { +public: + enum class Flag : int32 { + MAX_FIELD = (1 << 0), + }; + Q_DECLARE_FLAGS(Flags, Flag); + friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } + + MTPDinputBotInlineResultGame() { + } + MTPDinputBotInlineResultGame(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) : vflags(_flags), vid(_id), vshort_name(_short_name), vsend_message(_send_message) { + } + + MTPflags vflags; + MTPstring vid; + MTPstring vshort_name; + MTPInputBotInlineMessage vsend_message; +}; + class MTPDbotInlineMessageMediaAuto : public mtpDataImpl { public: enum class Flag : int32 { @@ -15036,6 +15309,78 @@ public: MTPInputDocument vid; }; +class MTPDgame : public mtpDataImpl { +public: + enum class Flag : int32 { + f_document = (1 << 0), + MAX_FIELD = (1 << 0), + }; + Q_DECLARE_FLAGS(Flags, Flag); + friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } + + bool has_document() const { return vflags.v & Flag::f_document; } + + MTPDgame() { + } + MTPDgame(const MTPflags &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vshort_name(_short_name), vtitle(_title), vdescription(_description), vurl(_url), vphoto(_photo), vdocument(_document) { + } + + MTPflags vflags; + MTPlong vid; + MTPlong vaccess_hash; + MTPstring vshort_name; + MTPstring vtitle; + MTPstring vdescription; + MTPstring vurl; + MTPPhoto vphoto; + MTPDocument vdocument; +}; + +class MTPDinputGameID : public mtpDataImpl { +public: + MTPDinputGameID() { + } + MTPDinputGameID(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { + } + + MTPlong vid; + MTPlong vaccess_hash; +}; + +class MTPDinputGameShortName : public mtpDataImpl { +public: + MTPDinputGameShortName() { + } + MTPDinputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) : vbot_id(_bot_id), vshort_name(_short_name) { + } + + MTPInputUser vbot_id; + MTPstring vshort_name; +}; + +class MTPDhighScore : public mtpDataImpl { +public: + MTPDhighScore() { + } + MTPDhighScore(MTPint _pos, MTPint _user_id, MTPint _score) : vpos(_pos), vuser_id(_user_id), vscore(_score) { + } + + MTPint vpos; + MTPint vuser_id; + MTPint vscore; +}; + +class MTPDmessages_highScores : public mtpDataImpl { +public: + MTPDmessages_highScores() { + } + MTPDmessages_highScores(const MTPVector &_scores, const MTPVector &_users) : vscores(_scores), vusers(_users) { + } + + MTPVector vscores; + MTPVector vusers; +}; + // RPC methods class MTPreq_pq { // RPC method 'req_pq' @@ -20847,33 +21192,32 @@ public: class MTPmessages_getBotCallbackAnswer { // RPC method 'messages.getBotCallbackAnswer' public: enum class Flag : int32 { + f_game = (1 << 1), f_data = (1 << 0), - f_game_id = (1 << 1), MAX_FIELD = (1 << 1), }; Q_DECLARE_FLAGS(Flags, Flag); friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } + bool is_game() const { return vflags.v & Flag::f_game; } bool has_data() const { return vflags.v & Flag::f_data; } - bool has_game_id() const { return vflags.v & Flag::f_game_id; } MTPflags vflags; MTPInputPeer vpeer; MTPint vmsg_id; MTPbytes vdata; - MTPint vgame_id; MTPmessages_getBotCallbackAnswer() { } MTPmessages_getBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getBotCallbackAnswer) { read(from, end, cons); } - MTPmessages_getBotCallbackAnswer(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vpeer(_peer), vmsg_id(_msg_id), vdata(_data), vgame_id(_game_id) { + MTPmessages_getBotCallbackAnswer(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data) : vflags(_flags), vpeer(_peer), vmsg_id(_msg_id), vdata(_data) { } uint32 innerLength() const { - return vflags.innerLength() + vpeer.innerLength() + vmsg_id.innerLength() + (has_data() ? vdata.innerLength() : 0) + (has_game_id() ? vgame_id.innerLength() : 0); + return vflags.innerLength() + vpeer.innerLength() + vmsg_id.innerLength() + (has_data() ? vdata.innerLength() : 0); } mtpTypeId type() const { return mtpc_messages_getBotCallbackAnswer; @@ -20883,14 +21227,12 @@ public: vpeer.read(from, end); vmsg_id.read(from, end); if (has_data()) { vdata.read(from, end); } else { vdata = MTPbytes(); } - if (has_game_id()) { vgame_id.read(from, end); } else { vgame_id = MTPint(); } } void write(mtpBuffer &to) const { vflags.write(to); vpeer.write(to); vmsg_id.write(to); if (has_data()) vdata.write(to); - if (has_game_id()) vgame_id.write(to); } typedef MTPmessages_BotCallbackAnswer ResponseType; @@ -20905,7 +21247,7 @@ public: } MTPmessages_GetBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPmessages_GetBotCallbackAnswer(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data, MTPint _game_id) : MTPBoxed(MTPmessages_getBotCallbackAnswer(_flags, _peer, _msg_id, _data, _game_id)) { + MTPmessages_GetBotCallbackAnswer(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data) : MTPBoxed(MTPmessages_getBotCallbackAnswer(_flags, _peer, _msg_id, _data)) { } }; @@ -21403,133 +21745,6 @@ public: } }; -class MTPmessages_setGameScore { // RPC method 'messages.setGameScore' -public: - enum class Flag : int32 { - f_edit_message = (1 << 0), - MAX_FIELD = (1 << 0), - }; - Q_DECLARE_FLAGS(Flags, Flag); - friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } - - bool is_edit_message() const { return vflags.v & Flag::f_edit_message; } - - MTPflags vflags; - MTPInputPeer vpeer; - MTPint vid; - MTPInputUser vuser_id; - MTPint vgame_id; - MTPint vscore; - - MTPmessages_setGameScore() { - } - MTPmessages_setGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) { - read(from, end, cons); - } - MTPmessages_setGameScore(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : vflags(_flags), vpeer(_peer), vid(_id), vuser_id(_user_id), vgame_id(_game_id), vscore(_score) { - } - - uint32 innerLength() const { - return vflags.innerLength() + vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength() + vgame_id.innerLength() + vscore.innerLength(); - } - mtpTypeId type() const { - return mtpc_messages_setGameScore; - } - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) { - vflags.read(from, end); - vpeer.read(from, end); - vid.read(from, end); - vuser_id.read(from, end); - vgame_id.read(from, end); - vscore.read(from, end); - } - void write(mtpBuffer &to) const { - vflags.write(to); - vpeer.write(to); - vid.write(to); - vuser_id.write(to); - vgame_id.write(to); - vscore.write(to); - } - - typedef MTPUpdates ResponseType; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setGameScore::Flags) - -class MTPmessages_SetGameScore : public MTPBoxed { -public: - MTPmessages_SetGameScore() { - } - MTPmessages_SetGameScore(const MTPmessages_setGameScore &v) : MTPBoxed(v) { - } - MTPmessages_SetGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { - } - MTPmessages_SetGameScore(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : MTPBoxed(MTPmessages_setGameScore(_flags, _peer, _id, _user_id, _game_id, _score)) { - } -}; - -class MTPmessages_setInlineGameScore { // RPC method 'messages.setInlineGameScore' -public: - enum class Flag : int32 { - f_edit_message = (1 << 0), - MAX_FIELD = (1 << 0), - }; - Q_DECLARE_FLAGS(Flags, Flag); - friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } - - bool is_edit_message() const { return vflags.v & Flag::f_edit_message; } - - MTPflags vflags; - MTPInputBotInlineMessageID vid; - MTPInputUser vuser_id; - MTPint vgame_id; - MTPint vscore; - - MTPmessages_setInlineGameScore() { - } - MTPmessages_setInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) { - read(from, end, cons); - } - MTPmessages_setInlineGameScore(const MTPflags &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : vflags(_flags), vid(_id), vuser_id(_user_id), vgame_id(_game_id), vscore(_score) { - } - - uint32 innerLength() const { - return vflags.innerLength() + vid.innerLength() + vuser_id.innerLength() + vgame_id.innerLength() + vscore.innerLength(); - } - mtpTypeId type() const { - return mtpc_messages_setInlineGameScore; - } - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) { - vflags.read(from, end); - vid.read(from, end); - vuser_id.read(from, end); - vgame_id.read(from, end); - vscore.read(from, end); - } - void write(mtpBuffer &to) const { - vflags.write(to); - vid.write(to); - vuser_id.write(to); - vgame_id.write(to); - vscore.write(to); - } - - typedef MTPBool ResponseType; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setInlineGameScore::Flags) - -class MTPmessages_SetInlineGameScore : public MTPBoxed { -public: - MTPmessages_SetInlineGameScore() { - } - MTPmessages_SetInlineGameScore(const MTPmessages_setInlineGameScore &v) : MTPBoxed(v) { - } - MTPmessages_SetInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { - } - MTPmessages_SetInlineGameScore(const MTPflags &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : MTPBoxed(MTPmessages_setInlineGameScore(_flags, _id, _user_id, _game_id, _score)) { - } -}; - class MTPmessages_getMaskStickers { // RPC method 'messages.getMaskStickers' public: MTPint vhash; @@ -21608,6 +21823,214 @@ public: } }; +class MTPmessages_setGameScore { // RPC method 'messages.setGameScore' +public: + enum class Flag : int32 { + f_edit_message = (1 << 0), + MAX_FIELD = (1 << 0), + }; + Q_DECLARE_FLAGS(Flags, Flag); + friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } + + bool is_edit_message() const { return vflags.v & Flag::f_edit_message; } + + MTPflags vflags; + MTPInputPeer vpeer; + MTPint vid; + MTPInputUser vuser_id; + MTPint vscore; + + MTPmessages_setGameScore() { + } + MTPmessages_setGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) { + read(from, end, cons); + } + MTPmessages_setGameScore(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _score) : vflags(_flags), vpeer(_peer), vid(_id), vuser_id(_user_id), vscore(_score) { + } + + uint32 innerLength() const { + return vflags.innerLength() + vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength() + vscore.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_setGameScore; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) { + vflags.read(from, end); + vpeer.read(from, end); + vid.read(from, end); + vuser_id.read(from, end); + vscore.read(from, end); + } + void write(mtpBuffer &to) const { + vflags.write(to); + vpeer.write(to); + vid.write(to); + vuser_id.write(to); + vscore.write(to); + } + + typedef MTPUpdates ResponseType; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setGameScore::Flags) + +class MTPmessages_SetGameScore : public MTPBoxed { +public: + MTPmessages_SetGameScore() { + } + MTPmessages_SetGameScore(const MTPmessages_setGameScore &v) : MTPBoxed(v) { + } + MTPmessages_SetGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SetGameScore(const MTPflags &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _score) : MTPBoxed(MTPmessages_setGameScore(_flags, _peer, _id, _user_id, _score)) { + } +}; + +class MTPmessages_setInlineGameScore { // RPC method 'messages.setInlineGameScore' +public: + enum class Flag : int32 { + f_edit_message = (1 << 0), + MAX_FIELD = (1 << 0), + }; + Q_DECLARE_FLAGS(Flags, Flag); + friend inline Flags operator~(Flag v) { return QFlag(~static_cast(v)); } + + bool is_edit_message() const { return vflags.v & Flag::f_edit_message; } + + MTPflags vflags; + MTPInputBotInlineMessageID vid; + MTPInputUser vuser_id; + MTPint vscore; + + MTPmessages_setInlineGameScore() { + } + MTPmessages_setInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) { + read(from, end, cons); + } + MTPmessages_setInlineGameScore(const MTPflags &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _score) : vflags(_flags), vid(_id), vuser_id(_user_id), vscore(_score) { + } + + uint32 innerLength() const { + return vflags.innerLength() + vid.innerLength() + vuser_id.innerLength() + vscore.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_setInlineGameScore; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) { + vflags.read(from, end); + vid.read(from, end); + vuser_id.read(from, end); + vscore.read(from, end); + } + void write(mtpBuffer &to) const { + vflags.write(to); + vid.write(to); + vuser_id.write(to); + vscore.write(to); + } + + typedef MTPBool ResponseType; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setInlineGameScore::Flags) + +class MTPmessages_SetInlineGameScore : public MTPBoxed { +public: + MTPmessages_SetInlineGameScore() { + } + MTPmessages_SetInlineGameScore(const MTPmessages_setInlineGameScore &v) : MTPBoxed(v) { + } + MTPmessages_SetInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_SetInlineGameScore(const MTPflags &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _score) : MTPBoxed(MTPmessages_setInlineGameScore(_flags, _id, _user_id, _score)) { + } +}; + +class MTPmessages_getGameHighScores { // RPC method 'messages.getGameHighScores' +public: + MTPInputPeer vpeer; + MTPint vid; + MTPInputUser vuser_id; + + MTPmessages_getGameHighScores() { + } + MTPmessages_getGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getGameHighScores) { + read(from, end, cons); + } + MTPmessages_getGameHighScores(const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id) : vpeer(_peer), vid(_id), vuser_id(_user_id) { + } + + uint32 innerLength() const { + return vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getGameHighScores; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getGameHighScores) { + vpeer.read(from, end); + vid.read(from, end); + vuser_id.read(from, end); + } + void write(mtpBuffer &to) const { + vpeer.write(to); + vid.write(to); + vuser_id.write(to); + } + + typedef MTPmessages_HighScores ResponseType; +}; +class MTPmessages_GetGameHighScores : public MTPBoxed { +public: + MTPmessages_GetGameHighScores() { + } + MTPmessages_GetGameHighScores(const MTPmessages_getGameHighScores &v) : MTPBoxed(v) { + } + MTPmessages_GetGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetGameHighScores(const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id) : MTPBoxed(MTPmessages_getGameHighScores(_peer, _id, _user_id)) { + } +}; + +class MTPmessages_getInlineGameHighScores { // RPC method 'messages.getInlineGameHighScores' +public: + MTPInputBotInlineMessageID vid; + MTPInputUser vuser_id; + + MTPmessages_getInlineGameHighScores() { + } + MTPmessages_getInlineGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getInlineGameHighScores) { + read(from, end, cons); + } + MTPmessages_getInlineGameHighScores(const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id) : vid(_id), vuser_id(_user_id) { + } + + uint32 innerLength() const { + return vid.innerLength() + vuser_id.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_getInlineGameHighScores; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getInlineGameHighScores) { + vid.read(from, end); + vuser_id.read(from, end); + } + void write(mtpBuffer &to) const { + vid.write(to); + vuser_id.write(to); + } + + typedef MTPmessages_HighScores ResponseType; +}; +class MTPmessages_GetInlineGameHighScores : public MTPBoxed { +public: + MTPmessages_GetInlineGameHighScores() { + } + MTPmessages_GetInlineGameHighScores(const MTPmessages_getInlineGameHighScores &v) : MTPBoxed(v) { + } + MTPmessages_GetInlineGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_GetInlineGameHighScores(const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id) : MTPBoxed(MTPmessages_getInlineGameHighScores(_id, _user_id)) { + } +}; + class MTPupdates_getState { // RPC method 'updates.getState' public: MTPupdates_getState() { @@ -23619,6 +24042,9 @@ public: inline static MTPinputMedia new_inputMediaDocumentExternal(const MTPstring &_url, const MTPstring &_caption) { return MTPinputMedia(new MTPDinputMediaDocumentExternal(_url, _caption)); } + inline static MTPinputMedia new_inputMediaGame(const MTPInputGame &_id) { + return MTPinputMedia(new MTPDinputMediaGame(_id)); + } inline static MTPinputChatPhoto new_inputChatPhotoEmpty() { return MTPinputChatPhoto(mtpc_inputChatPhotoEmpty); } @@ -23802,6 +24228,9 @@ public: inline static MTPmessageMedia new_messageMediaVenue(const MTPGeoPoint &_geo, const MTPstring &_title, const MTPstring &_address, const MTPstring &_provider, const MTPstring &_venue_id) { return MTPmessageMedia(new MTPDmessageMediaVenue(_geo, _title, _address, _provider, _venue_id)); } + inline static MTPmessageMedia new_messageMediaGame(const MTPGame &_game) { + return MTPmessageMedia(new MTPDmessageMediaGame(_game)); + } inline static MTPmessageAction new_messageActionEmpty() { return MTPmessageAction(mtpc_messageActionEmpty); } @@ -23841,7 +24270,7 @@ public: inline static MTPmessageAction new_messageActionHistoryClear() { return MTPmessageAction(mtpc_messageActionHistoryClear); } - inline static MTPmessageAction new_messageActionGameScore(MTPint _game_id, MTPint _score) { + inline static MTPmessageAction new_messageActionGameScore(const MTPlong &_game_id, MTPint _score) { return MTPmessageAction(new MTPDmessageActionGameScore(_game_id, _score)); } inline static MTPdialog new_dialog(const MTPflags &_flags, const MTPPeer &_peer, MTPint _top_message, MTPint _read_inbox_max_id, MTPint _read_outbox_max_id, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings, MTPint _pts, const MTPDraftMessage &_draft) { @@ -24156,14 +24585,14 @@ public: inline static MTPupdate new_updateChannelPinnedMessage(MTPint _channel_id, MTPint _id) { return MTPupdate(new MTPDupdateChannelPinnedMessage(_channel_id, _id)); } - inline static MTPupdate new_updateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) { - return MTPupdate(new MTPDupdateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_id)); + inline static MTPupdate new_updateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) { + return MTPupdate(new MTPDupdateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_short_name)); } inline static MTPupdate new_updateEditMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) { return MTPupdate(new MTPDupdateEditMessage(_message, _pts, _pts_count)); } - inline static MTPupdate new_updateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) { - return MTPupdate(new MTPDupdateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_id)); + inline static MTPupdate new_updateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) { + return MTPupdate(new MTPDupdateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_short_name)); } inline static MTPupdate new_updateReadChannelOutbox(MTPint _channel_id, MTPint _max_id) { return MTPupdate(new MTPDupdateReadChannelOutbox(_channel_id, _max_id)); @@ -24552,8 +24981,8 @@ public: inline static MTPkeyboardButton new_keyboardButtonSwitchInline(const MTPflags &_flags, const MTPstring &_text, const MTPstring &_query) { return MTPkeyboardButton(new MTPDkeyboardButtonSwitchInline(_flags, _text, _query)); } - inline static MTPkeyboardButton new_keyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) { - return MTPkeyboardButton(new MTPDkeyboardButtonGame(_text, _game_title, _game_id, _start_param)); + inline static MTPkeyboardButton new_keyboardButtonGame(const MTPstring &_text) { + return MTPkeyboardButton(new MTPDkeyboardButtonGame(_text)); } inline static MTPkeyboardButtonRow new_keyboardButtonRow(const MTPVector &_buttons) { return MTPkeyboardButtonRow(new MTPDkeyboardButtonRow(_buttons)); @@ -24720,6 +25149,9 @@ public: inline static MTPinputBotInlineMessage new_inputBotInlineMessageMediaContact(const MTPflags &_flags, const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, const MTPReplyMarkup &_reply_markup) { return MTPinputBotInlineMessage(new MTPDinputBotInlineMessageMediaContact(_flags, _phone_number, _first_name, _last_name, _reply_markup)); } + inline static MTPinputBotInlineMessage new_inputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) { + return MTPinputBotInlineMessage(new MTPDinputBotInlineMessageGame(_reply_markup)); + } inline static MTPinputBotInlineResult new_inputBotInlineResult(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPstring &_thumb_url, const MTPstring &_content_url, const MTPstring &_content_type, MTPint _w, MTPint _h, MTPint _duration, const MTPInputBotInlineMessage &_send_message) { return MTPinputBotInlineResult(new MTPDinputBotInlineResult(_flags, _id, _type, _title, _description, _url, _thumb_url, _content_url, _content_type, _w, _h, _duration, _send_message)); } @@ -24729,6 +25161,9 @@ public: inline static MTPinputBotInlineResult new_inputBotInlineResultDocument(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) { return MTPinputBotInlineResult(new MTPDinputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message)); } + inline static MTPinputBotInlineResult new_inputBotInlineResultGame(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) { + return MTPinputBotInlineResult(new MTPDinputBotInlineResultGame(_flags, _id, _short_name, _send_message)); + } inline static MTPbotInlineMessage new_botInlineMessageMediaAuto(const MTPflags &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) { return MTPbotInlineMessage(new MTPDbotInlineMessageMediaAuto(_flags, _caption, _reply_markup)); } @@ -24864,6 +25299,21 @@ public: inline static MTPinputStickeredMedia new_inputStickeredMediaDocument(const MTPInputDocument &_id) { return MTPinputStickeredMedia(new MTPDinputStickeredMediaDocument(_id)); } + inline static MTPgame new_game(const MTPflags &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) { + return MTPgame(new MTPDgame(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document)); + } + inline static MTPinputGame new_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) { + return MTPinputGame(new MTPDinputGameID(_id, _access_hash)); + } + inline static MTPinputGame new_inputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) { + return MTPinputGame(new MTPDinputGameShortName(_bot_id, _short_name)); + } + inline static MTPhighScore new_highScore(MTPint _pos, MTPint _user_id, MTPint _score) { + return MTPhighScore(new MTPDhighScore(_pos, _user_id, _score)); + } + inline static MTPmessages_highScores new_messages_highScores(const MTPVector &_scores, const MTPVector &_users) { + return MTPmessages_highScores(new MTPDmessages_highScores(_scores, _users)); + } }; } // namespace internal @@ -26155,6 +26605,10 @@ inline uint32 MTPinputMedia::innerLength() const { const MTPDinputMediaDocumentExternal &v(c_inputMediaDocumentExternal()); return v.vurl.innerLength() + v.vcaption.innerLength(); } + case mtpc_inputMediaGame: { + const MTPDinputMediaGame &v(c_inputMediaGame()); + return v.vid.innerLength(); + } } return 0; } @@ -26246,6 +26700,11 @@ inline void MTPinputMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpT v.vurl.read(from, end); v.vcaption.read(from, end); } break; + case mtpc_inputMediaGame: _type = cons; { + if (!data) setData(new MTPDinputMediaGame()); + MTPDinputMediaGame &v(_inputMediaGame()); + v.vid.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPinputMedia"); } } @@ -26320,6 +26779,10 @@ inline void MTPinputMedia::write(mtpBuffer &to) const { v.vurl.write(to); v.vcaption.write(to); } break; + case mtpc_inputMediaGame: { + const MTPDinputMediaGame &v(c_inputMediaGame()); + v.vid.write(to); + } break; } } inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -26336,6 +26799,7 @@ inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : mtpDataOwner(0), _type(typ case mtpc_inputMediaGifExternal: setData(new MTPDinputMediaGifExternal()); break; case mtpc_inputMediaPhotoExternal: setData(new MTPDinputMediaPhotoExternal()); break; case mtpc_inputMediaDocumentExternal: setData(new MTPDinputMediaDocumentExternal()); break; + case mtpc_inputMediaGame: setData(new MTPDinputMediaGame()); break; default: throw mtpErrorBadTypeId(type, "MTPinputMedia"); } } @@ -26361,6 +26825,8 @@ inline MTPinputMedia::MTPinputMedia(MTPDinputMediaPhotoExternal *_data) : mtpDat } inline MTPinputMedia::MTPinputMedia(MTPDinputMediaDocumentExternal *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaDocumentExternal) { } +inline MTPinputMedia::MTPinputMedia(MTPDinputMediaGame *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaGame) { +} inline MTPinputMedia MTP_inputMediaEmpty() { return MTP::internal::TypeCreator::new_inputMediaEmpty(); } @@ -26400,6 +26866,9 @@ inline MTPinputMedia MTP_inputMediaPhotoExternal(const MTPstring &_url, const MT inline MTPinputMedia MTP_inputMediaDocumentExternal(const MTPstring &_url, const MTPstring &_caption) { return MTP::internal::TypeCreator::new_inputMediaDocumentExternal(_url, _caption); } +inline MTPinputMedia MTP_inputMediaGame(const MTPInputGame &_id) { + return MTP::internal::TypeCreator::new_inputMediaGame(_id); +} inline uint32 MTPinputChatPhoto::innerLength() const { switch (_type) { @@ -27769,6 +28238,10 @@ inline uint32 MTPmessageMedia::innerLength() const { const MTPDmessageMediaVenue &v(c_messageMediaVenue()); return v.vgeo.innerLength() + v.vtitle.innerLength() + v.vaddress.innerLength() + v.vprovider.innerLength() + v.vvenue_id.innerLength(); } + case mtpc_messageMediaGame: { + const MTPDmessageMediaGame &v(c_messageMediaGame()); + return v.vgame.innerLength(); + } } return 0; } @@ -27820,6 +28293,11 @@ inline void MTPmessageMedia::read(const mtpPrime *&from, const mtpPrime *end, mt v.vprovider.read(from, end); v.vvenue_id.read(from, end); } break; + case mtpc_messageMediaGame: _type = cons; { + if (!data) setData(new MTPDmessageMediaGame()); + MTPDmessageMediaGame &v(_messageMediaGame()); + v.vgame.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPmessageMedia"); } } @@ -27858,6 +28336,10 @@ inline void MTPmessageMedia::write(mtpBuffer &to) const { v.vprovider.write(to); v.vvenue_id.write(to); } break; + case mtpc_messageMediaGame: { + const MTPDmessageMediaGame &v(c_messageMediaGame()); + v.vgame.write(to); + } break; } } inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -27870,6 +28352,7 @@ inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : mtpDataOwner(0), _type case mtpc_messageMediaDocument: setData(new MTPDmessageMediaDocument()); break; case mtpc_messageMediaWebPage: setData(new MTPDmessageMediaWebPage()); break; case mtpc_messageMediaVenue: setData(new MTPDmessageMediaVenue()); break; + case mtpc_messageMediaGame: setData(new MTPDmessageMediaGame()); break; default: throw mtpErrorBadTypeId(type, "MTPmessageMedia"); } } @@ -27885,6 +28368,8 @@ inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaWebPage *_data) : mtpDat } inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaVenue *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaVenue) { } +inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaGame *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaGame) { +} inline MTPmessageMedia MTP_messageMediaEmpty() { return MTP::internal::TypeCreator::new_messageMediaEmpty(); } @@ -27909,6 +28394,9 @@ inline MTPmessageMedia MTP_messageMediaWebPage(const MTPWebPage &_webpage) { inline MTPmessageMedia MTP_messageMediaVenue(const MTPGeoPoint &_geo, const MTPstring &_title, const MTPstring &_address, const MTPstring &_provider, const MTPstring &_venue_id) { return MTP::internal::TypeCreator::new_messageMediaVenue(_geo, _title, _address, _provider, _venue_id); } +inline MTPmessageMedia MTP_messageMediaGame(const MTPGame &_game) { + return MTP::internal::TypeCreator::new_messageMediaGame(_game); +} inline uint32 MTPmessageAction::innerLength() const { switch (_type) { @@ -28147,7 +28635,7 @@ inline MTPmessageAction MTP_messageActionPinMessage() { inline MTPmessageAction MTP_messageActionHistoryClear() { return MTP::internal::TypeCreator::new_messageActionHistoryClear(); } -inline MTPmessageAction MTP_messageActionGameScore(MTPint _game_id, MTPint _score) { +inline MTPmessageAction MTP_messageActionGameScore(const MTPlong &_game_id, MTPint _score) { return MTP::internal::TypeCreator::new_messageActionGameScore(_game_id, _score); } @@ -29760,7 +30248,7 @@ inline uint32 MTPupdate::innerLength() const { } case mtpc_updateBotCallbackQuery: { const MTPDupdateBotCallbackQuery &v(c_updateBotCallbackQuery()); - return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vpeer.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_id() ? v.vgame_id.innerLength() : 0); + return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vpeer.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_short_name() ? v.vgame_short_name.innerLength() : 0); } case mtpc_updateEditMessage: { const MTPDupdateEditMessage &v(c_updateEditMessage()); @@ -29768,7 +30256,7 @@ inline uint32 MTPupdate::innerLength() const { } case mtpc_updateInlineBotCallbackQuery: { const MTPDupdateInlineBotCallbackQuery &v(c_updateInlineBotCallbackQuery()); - return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_id() ? v.vgame_id.innerLength() : 0); + return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_short_name() ? v.vgame_short_name.innerLength() : 0); } case mtpc_updateReadChannelOutbox: { const MTPDupdateReadChannelOutbox &v(c_updateReadChannelOutbox()); @@ -30087,7 +30575,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vmsg_id.read(from, end); v.vchat_instance.read(from, end); if (v.has_data()) { v.vdata.read(from, end); } else { v.vdata = MTPbytes(); } - if (v.has_game_id()) { v.vgame_id.read(from, end); } else { v.vgame_id = MTPint(); } + if (v.has_game_short_name()) { v.vgame_short_name.read(from, end); } else { v.vgame_short_name = MTPstring(); } } break; case mtpc_updateEditMessage: _type = cons; { if (!data) setData(new MTPDupdateEditMessage()); @@ -30105,7 +30593,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vmsg_id.read(from, end); v.vchat_instance.read(from, end); if (v.has_data()) { v.vdata.read(from, end); } else { v.vdata = MTPbytes(); } - if (v.has_game_id()) { v.vgame_id.read(from, end); } else { v.vgame_id = MTPint(); } + if (v.has_game_short_name()) { v.vgame_short_name.read(from, end); } else { v.vgame_short_name = MTPstring(); } } break; case mtpc_updateReadChannelOutbox: _type = cons; { if (!data) setData(new MTPDupdateReadChannelOutbox()); @@ -30382,7 +30870,7 @@ inline void MTPupdate::write(mtpBuffer &to) const { v.vmsg_id.write(to); v.vchat_instance.write(to); if (v.has_data()) v.vdata.write(to); - if (v.has_game_id()) v.vgame_id.write(to); + if (v.has_game_short_name()) v.vgame_short_name.write(to); } break; case mtpc_updateEditMessage: { const MTPDupdateEditMessage &v(c_updateEditMessage()); @@ -30398,7 +30886,7 @@ inline void MTPupdate::write(mtpBuffer &to) const { v.vmsg_id.write(to); v.vchat_instance.write(to); if (v.has_data()) v.vdata.write(to); - if (v.has_game_id()) v.vgame_id.write(to); + if (v.has_game_short_name()) v.vgame_short_name.write(to); } break; case mtpc_updateReadChannelOutbox: { const MTPDupdateReadChannelOutbox &v(c_updateReadChannelOutbox()); @@ -30701,15 +31189,15 @@ inline MTPupdate MTP_updateChannelPinnedMessage(MTPint _channel_id, MTPint _id) return MTP::internal::TypeCreator::new_updateChannelPinnedMessage(_channel_id, _id); } Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDupdateBotCallbackQuery::Flags) -inline MTPupdate MTP_updateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) { - return MTP::internal::TypeCreator::new_updateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_id); +inline MTPupdate MTP_updateBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) { + return MTP::internal::TypeCreator::new_updateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_short_name); } inline MTPupdate MTP_updateEditMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) { return MTP::internal::TypeCreator::new_updateEditMessage(_message, _pts, _pts_count); } Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDupdateInlineBotCallbackQuery::Flags) -inline MTPupdate MTP_updateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) { - return MTP::internal::TypeCreator::new_updateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_id); +inline MTPupdate MTP_updateInlineBotCallbackQuery(const MTPflags &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) { + return MTP::internal::TypeCreator::new_updateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_short_name); } inline MTPupdate MTP_updateReadChannelOutbox(MTPint _channel_id, MTPint _max_id) { return MTP::internal::TypeCreator::new_updateReadChannelOutbox(_channel_id, _max_id); @@ -33764,7 +34252,7 @@ inline uint32 MTPkeyboardButton::innerLength() const { } case mtpc_keyboardButtonGame: { const MTPDkeyboardButtonGame &v(c_keyboardButtonGame()); - return v.vtext.innerLength() + v.vgame_title.innerLength() + v.vgame_id.innerLength() + v.vstart_param.innerLength(); + return v.vtext.innerLength(); } } return 0; @@ -33814,9 +34302,6 @@ inline void MTPkeyboardButton::read(const mtpPrime *&from, const mtpPrime *end, if (!data) setData(new MTPDkeyboardButtonGame()); MTPDkeyboardButtonGame &v(_keyboardButtonGame()); v.vtext.read(from, end); - v.vgame_title.read(from, end); - v.vgame_id.read(from, end); - v.vstart_param.read(from, end); } break; default: throw mtpErrorUnexpected(cons, "MTPkeyboardButton"); } @@ -33854,9 +34339,6 @@ inline void MTPkeyboardButton::write(mtpBuffer &to) const { case mtpc_keyboardButtonGame: { const MTPDkeyboardButtonGame &v(c_keyboardButtonGame()); v.vtext.write(to); - v.vgame_title.write(to); - v.vgame_id.write(to); - v.vstart_param.write(to); } break; } } @@ -33905,8 +34387,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDkeyboardButtonSwitchInline::Flags) inline MTPkeyboardButton MTP_keyboardButtonSwitchInline(const MTPflags &_flags, const MTPstring &_text, const MTPstring &_query) { return MTP::internal::TypeCreator::new_keyboardButtonSwitchInline(_flags, _text, _query); } -inline MTPkeyboardButton MTP_keyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) { - return MTP::internal::TypeCreator::new_keyboardButtonGame(_text, _game_title, _game_id, _start_param); +inline MTPkeyboardButton MTP_keyboardButtonGame(const MTPstring &_text) { + return MTP::internal::TypeCreator::new_keyboardButtonGame(_text); } inline MTPkeyboardButtonRow::MTPkeyboardButtonRow() : mtpDataOwner(new MTPDkeyboardButtonRow()) { @@ -35177,6 +35659,10 @@ inline uint32 MTPinputBotInlineMessage::innerLength() const { const MTPDinputBotInlineMessageMediaContact &v(c_inputBotInlineMessageMediaContact()); return v.vflags.innerLength() + v.vphone_number.innerLength() + v.vfirst_name.innerLength() + v.vlast_name.innerLength() + (v.has_reply_markup() ? v.vreply_markup.innerLength() : 0); } + case mtpc_inputBotInlineMessageGame: { + const MTPDinputBotInlineMessageGame &v(c_inputBotInlineMessageGame()); + return v.vreply_markup.innerLength(); + } } return 0; } @@ -35229,6 +35715,11 @@ inline void MTPinputBotInlineMessage::read(const mtpPrime *&from, const mtpPrime v.vlast_name.read(from, end); if (v.has_reply_markup()) { v.vreply_markup.read(from, end); } else { v.vreply_markup = MTPReplyMarkup(); } } break; + case mtpc_inputBotInlineMessageGame: _type = cons; { + if (!data) setData(new MTPDinputBotInlineMessageGame()); + MTPDinputBotInlineMessageGame &v(_inputBotInlineMessageGame()); + v.vreply_markup.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPinputBotInlineMessage"); } } @@ -35271,6 +35762,10 @@ inline void MTPinputBotInlineMessage::write(mtpBuffer &to) const { v.vlast_name.write(to); if (v.has_reply_markup()) v.vreply_markup.write(to); } break; + case mtpc_inputBotInlineMessageGame: { + const MTPDinputBotInlineMessageGame &v(c_inputBotInlineMessageGame()); + v.vreply_markup.write(to); + } break; } } inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -35280,6 +35775,7 @@ inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(mtpTypeId type) : mtpD case mtpc_inputBotInlineMessageMediaGeo: setData(new MTPDinputBotInlineMessageMediaGeo()); break; case mtpc_inputBotInlineMessageMediaVenue: setData(new MTPDinputBotInlineMessageMediaVenue()); break; case mtpc_inputBotInlineMessageMediaContact: setData(new MTPDinputBotInlineMessageMediaContact()); break; + case mtpc_inputBotInlineMessageGame: setData(new MTPDinputBotInlineMessageGame()); break; default: throw mtpErrorBadTypeId(type, "MTPinputBotInlineMessage"); } } @@ -35293,6 +35789,8 @@ inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMess } inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaContact *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineMessageMediaContact) { } +inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMessageGame *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineMessageGame) { +} Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineMessageMediaAuto::Flags) inline MTPinputBotInlineMessage MTP_inputBotInlineMessageMediaAuto(const MTPflags &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) { return MTP::internal::TypeCreator::new_inputBotInlineMessageMediaAuto(_flags, _caption, _reply_markup); @@ -35313,6 +35811,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineMessageMediaContact::Flags) inline MTPinputBotInlineMessage MTP_inputBotInlineMessageMediaContact(const MTPflags &_flags, const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, const MTPReplyMarkup &_reply_markup) { return MTP::internal::TypeCreator::new_inputBotInlineMessageMediaContact(_flags, _phone_number, _first_name, _last_name, _reply_markup); } +inline MTPinputBotInlineMessage MTP_inputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) { + return MTP::internal::TypeCreator::new_inputBotInlineMessageGame(_reply_markup); +} inline uint32 MTPinputBotInlineResult::innerLength() const { switch (_type) { @@ -35328,6 +35829,10 @@ inline uint32 MTPinputBotInlineResult::innerLength() const { const MTPDinputBotInlineResultDocument &v(c_inputBotInlineResultDocument()); return v.vflags.innerLength() + v.vid.innerLength() + v.vtype.innerLength() + (v.has_title() ? v.vtitle.innerLength() : 0) + (v.has_description() ? v.vdescription.innerLength() : 0) + v.vdocument.innerLength() + v.vsend_message.innerLength(); } + case mtpc_inputBotInlineResultGame: { + const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame()); + return v.vflags.innerLength() + v.vid.innerLength() + v.vshort_name.innerLength() + v.vsend_message.innerLength(); + } } return 0; } @@ -35374,6 +35879,14 @@ inline void MTPinputBotInlineResult::read(const mtpPrime *&from, const mtpPrime v.vdocument.read(from, end); v.vsend_message.read(from, end); } break; + case mtpc_inputBotInlineResultGame: _type = cons; { + if (!data) setData(new MTPDinputBotInlineResultGame()); + MTPDinputBotInlineResultGame &v(_inputBotInlineResultGame()); + v.vflags.read(from, end); + v.vid.read(from, end); + v.vshort_name.read(from, end); + v.vsend_message.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPinputBotInlineResult"); } } @@ -35412,6 +35925,13 @@ inline void MTPinputBotInlineResult::write(mtpBuffer &to) const { v.vdocument.write(to); v.vsend_message.write(to); } break; + case mtpc_inputBotInlineResultGame: { + const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame()); + v.vflags.write(to); + v.vid.write(to); + v.vshort_name.write(to); + v.vsend_message.write(to); + } break; } } inline MTPinputBotInlineResult::MTPinputBotInlineResult(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -35419,6 +35939,7 @@ inline MTPinputBotInlineResult::MTPinputBotInlineResult(mtpTypeId type) : mtpDat case mtpc_inputBotInlineResult: setData(new MTPDinputBotInlineResult()); break; case mtpc_inputBotInlineResultPhoto: setData(new MTPDinputBotInlineResultPhoto()); break; case mtpc_inputBotInlineResultDocument: setData(new MTPDinputBotInlineResultDocument()); break; + case mtpc_inputBotInlineResultGame: setData(new MTPDinputBotInlineResultGame()); break; default: throw mtpErrorBadTypeId(type, "MTPinputBotInlineResult"); } } @@ -35428,6 +35949,8 @@ inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResult } inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResultDocument *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineResultDocument) { } +inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResultGame *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineResultGame) { +} Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineResult::Flags) inline MTPinputBotInlineResult MTP_inputBotInlineResult(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPstring &_thumb_url, const MTPstring &_content_url, const MTPstring &_content_type, MTPint _w, MTPint _h, MTPint _duration, const MTPInputBotInlineMessage &_send_message) { return MTP::internal::TypeCreator::new_inputBotInlineResult(_flags, _id, _type, _title, _description, _url, _thumb_url, _content_url, _content_type, _w, _h, _duration, _send_message); @@ -35439,6 +35962,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineResultDocument::Flags) inline MTPinputBotInlineResult MTP_inputBotInlineResultDocument(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) { return MTP::internal::TypeCreator::new_inputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message); } +inline MTPinputBotInlineResult MTP_inputBotInlineResultGame(const MTPflags &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) { + return MTP::internal::TypeCreator::new_inputBotInlineResultGame(_flags, _id, _short_name, _send_message); +} inline uint32 MTPbotInlineMessage::innerLength() const { switch (_type) { @@ -36652,6 +37178,177 @@ inline MTPinputStickeredMedia MTP_inputStickeredMediaPhoto(const MTPInputPhoto & inline MTPinputStickeredMedia MTP_inputStickeredMediaDocument(const MTPInputDocument &_id) { return MTP::internal::TypeCreator::new_inputStickeredMediaDocument(_id); } + +inline MTPgame::MTPgame() : mtpDataOwner(new MTPDgame()) { +} + +inline uint32 MTPgame::innerLength() const { + const MTPDgame &v(c_game()); + return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vshort_name.innerLength() + v.vtitle.innerLength() + v.vdescription.innerLength() + v.vurl.innerLength() + v.vphoto.innerLength() + (v.has_document() ? v.vdocument.innerLength() : 0); +} +inline mtpTypeId MTPgame::type() const { + return mtpc_game; +} +inline void MTPgame::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_game) throw mtpErrorUnexpected(cons, "MTPgame"); + + if (!data) setData(new MTPDgame()); + MTPDgame &v(_game()); + v.vflags.read(from, end); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + v.vshort_name.read(from, end); + v.vtitle.read(from, end); + v.vdescription.read(from, end); + v.vurl.read(from, end); + v.vphoto.read(from, end); + if (v.has_document()) { v.vdocument.read(from, end); } else { v.vdocument = MTPDocument(); } +} +inline void MTPgame::write(mtpBuffer &to) const { + const MTPDgame &v(c_game()); + v.vflags.write(to); + v.vid.write(to); + v.vaccess_hash.write(to); + v.vshort_name.write(to); + v.vtitle.write(to); + v.vdescription.write(to); + v.vurl.write(to); + v.vphoto.write(to); + if (v.has_document()) v.vdocument.write(to); +} +inline MTPgame::MTPgame(MTPDgame *_data) : mtpDataOwner(_data) { +} +Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDgame::Flags) +inline MTPgame MTP_game(const MTPflags &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) { + return MTP::internal::TypeCreator::new_game(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document); +} + +inline uint32 MTPinputGame::innerLength() const { + switch (_type) { + case mtpc_inputGameID: { + const MTPDinputGameID &v(c_inputGameID()); + return v.vid.innerLength() + v.vaccess_hash.innerLength(); + } + case mtpc_inputGameShortName: { + const MTPDinputGameShortName &v(c_inputGameShortName()); + return v.vbot_id.innerLength() + v.vshort_name.innerLength(); + } + } + return 0; +} +inline mtpTypeId MTPinputGame::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPinputGame::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != _type) setData(0); + switch (cons) { + case mtpc_inputGameID: _type = cons; { + if (!data) setData(new MTPDinputGameID()); + MTPDinputGameID &v(_inputGameID()); + v.vid.read(from, end); + v.vaccess_hash.read(from, end); + } break; + case mtpc_inputGameShortName: _type = cons; { + if (!data) setData(new MTPDinputGameShortName()); + MTPDinputGameShortName &v(_inputGameShortName()); + v.vbot_id.read(from, end); + v.vshort_name.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPinputGame"); + } +} +inline void MTPinputGame::write(mtpBuffer &to) const { + switch (_type) { + case mtpc_inputGameID: { + const MTPDinputGameID &v(c_inputGameID()); + v.vid.write(to); + v.vaccess_hash.write(to); + } break; + case mtpc_inputGameShortName: { + const MTPDinputGameShortName &v(c_inputGameShortName()); + v.vbot_id.write(to); + v.vshort_name.write(to); + } break; + } +} +inline MTPinputGame::MTPinputGame(mtpTypeId type) : mtpDataOwner(0), _type(type) { + switch (type) { + case mtpc_inputGameID: setData(new MTPDinputGameID()); break; + case mtpc_inputGameShortName: setData(new MTPDinputGameShortName()); break; + default: throw mtpErrorBadTypeId(type, "MTPinputGame"); + } +} +inline MTPinputGame::MTPinputGame(MTPDinputGameID *_data) : mtpDataOwner(_data), _type(mtpc_inputGameID) { +} +inline MTPinputGame::MTPinputGame(MTPDinputGameShortName *_data) : mtpDataOwner(_data), _type(mtpc_inputGameShortName) { +} +inline MTPinputGame MTP_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) { + return MTP::internal::TypeCreator::new_inputGameID(_id, _access_hash); +} +inline MTPinputGame MTP_inputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) { + return MTP::internal::TypeCreator::new_inputGameShortName(_bot_id, _short_name); +} + +inline MTPhighScore::MTPhighScore() : mtpDataOwner(new MTPDhighScore()) { +} + +inline uint32 MTPhighScore::innerLength() const { + const MTPDhighScore &v(c_highScore()); + return v.vpos.innerLength() + v.vuser_id.innerLength() + v.vscore.innerLength(); +} +inline mtpTypeId MTPhighScore::type() const { + return mtpc_highScore; +} +inline void MTPhighScore::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_highScore) throw mtpErrorUnexpected(cons, "MTPhighScore"); + + if (!data) setData(new MTPDhighScore()); + MTPDhighScore &v(_highScore()); + v.vpos.read(from, end); + v.vuser_id.read(from, end); + v.vscore.read(from, end); +} +inline void MTPhighScore::write(mtpBuffer &to) const { + const MTPDhighScore &v(c_highScore()); + v.vpos.write(to); + v.vuser_id.write(to); + v.vscore.write(to); +} +inline MTPhighScore::MTPhighScore(MTPDhighScore *_data) : mtpDataOwner(_data) { +} +inline MTPhighScore MTP_highScore(MTPint _pos, MTPint _user_id, MTPint _score) { + return MTP::internal::TypeCreator::new_highScore(_pos, _user_id, _score); +} + +inline MTPmessages_highScores::MTPmessages_highScores() : mtpDataOwner(new MTPDmessages_highScores()) { +} + +inline uint32 MTPmessages_highScores::innerLength() const { + const MTPDmessages_highScores &v(c_messages_highScores()); + return v.vscores.innerLength() + v.vusers.innerLength(); +} +inline mtpTypeId MTPmessages_highScores::type() const { + return mtpc_messages_highScores; +} +inline void MTPmessages_highScores::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + if (cons != mtpc_messages_highScores) throw mtpErrorUnexpected(cons, "MTPmessages_highScores"); + + if (!data) setData(new MTPDmessages_highScores()); + MTPDmessages_highScores &v(_messages_highScores()); + v.vscores.read(from, end); + v.vusers.read(from, end); +} +inline void MTPmessages_highScores::write(mtpBuffer &to) const { + const MTPDmessages_highScores &v(c_messages_highScores()); + v.vscores.write(to); + v.vusers.write(to); +} +inline MTPmessages_highScores::MTPmessages_highScores(MTPDmessages_highScores *_data) : mtpDataOwner(_data) { +} +inline MTPmessages_highScores MTP_messages_highScores(const MTPVector &_scores, const MTPVector &_users) { + return MTP::internal::TypeCreator::new_messages_highScores(_scores, _users); +} inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } inline MTPDmessage::Flags mtpCastFlags(MTPflags flags) { return mtpCastFlags(flags.v); } inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); } diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 752546ac0e..dad19fdabc 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -888,13 +888,13 @@ bool Document::updateStatusText() const { Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) { AddComponents(Info::Bit()); - const auto textWithEntities = _parent->originalText(); + auto textWithEntities = _parent->originalText(); QString mainUrl; auto text = textWithEntities.text; auto &entities = textWithEntities.entities; int32 from = 0, till = text.size(), lnk = entities.size(); - for_const (const auto &entity, entities) { + for_const (auto &entity, entities) { auto type = entity.type(); if (type != EntityInTextUrl && type != EntityInTextCustomUrl && type != EntityInTextEmail) { continue; @@ -908,7 +908,7 @@ Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) { } while (lnk > 0 && till > from) { --lnk; - const auto &entity = entities.at(lnk); + auto &entity = entities.at(lnk); auto type = entity.type(); if (type != EntityInTextUrl && type != EntityInTextCustomUrl && type != EntityInTextEmail) { ++lnk; diff --git a/Telegram/SourceFiles/pspecific_win.cpp b/Telegram/SourceFiles/pspecific_win.cpp index 636db7fddc..61fcde541b 100644 --- a/Telegram/SourceFiles/pspecific_win.cpp +++ b/Telegram/SourceFiles/pspecific_win.cpp @@ -29,6 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "application.h" #include "mainwidget.h" +#include "history/history_location_manager.h" #include "localstorage.h" diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 82a9867529..e0b2d22016 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -717,11 +717,11 @@ void PhotoData::cancel() { } void PhotoData::notifyLayoutChanged() const { - const PhotoItems &items(App::photoItems()); - PhotoItems::const_iterator i = items.constFind(const_cast(this)); + auto &items = App::photoItems(); + auto i = items.constFind(const_cast(this)); if (i != items.cend()) { - for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - Notify::historyItemLayoutChanged(j.key()); + for_const (auto item, i.value()) { + Notify::historyItemLayoutChanged(item); } } } @@ -1441,12 +1441,9 @@ void DocumentData::cancel() { } void DocumentData::notifyLayoutChanged() const { - const DocumentItems &items(App::documentItems()); - DocumentItems::const_iterator i = items.constFind(const_cast(this)); - if (i != items.cend()) { - for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - Notify::historyItemLayoutChanged(j.key()); - } + auto &items = App::documentItems(); + for (auto item : items.value(const_cast(this))) { + Notify::historyItemLayoutChanged(item); } if (auto items = InlineBots::Layout::documentItems()) { @@ -1632,6 +1629,16 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u , pendingTill(pendingTill) { } +GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) : id(id) +, accessHash(accessHash) +, shortName(shortName) +, title(title) +, description(description) +, url(url) +, photo(photo) +, document(document) { +} + void PeerOpenClickHandler::onClickImpl() const { if (App::main()) { if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) { @@ -1651,18 +1658,3 @@ MsgId clientMsgId() { Q_ASSERT(currentClientMsgId < EndClientMsgId); return currentClientMsgId++; } - -QString LocationClickHandler::copyToClipboardContextItemText() const { - return lang(lng_context_copy_link); -} - -void LocationClickHandler::onClick(Qt::MouseButton button) const { - if (!psLaunchMaps(_coords)) { - QDesktopServices::openUrl(_text); - } -} - -void LocationClickHandler::setup() { - QString latlon(qsl("%1,%2").arg(_coords.lat).arg(_coords.lon)); - _text = qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16"); -} diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 85c8bd0284..acabe10219 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -137,11 +137,12 @@ inline TimeId dateFromMessage(const MTPmessage &msg) { return 0; } -typedef uint64 PhotoId; -typedef uint64 VideoId; -typedef uint64 AudioId; -typedef uint64 DocumentId; -typedef uint64 WebPageId; +using PhotoId = uint64; +using VideoId = uint64; +using AudioId = uint64; +using DocumentId = uint64; +using WebPageId = uint64; +using GameId = uint64; static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL; inline bool operator==(const FullMsgId &a, const FullMsgId &b) { @@ -1351,6 +1352,7 @@ struct WebPageData { WebPageData(const WebPageId &id, WebPageType type = WebPageArticle, const QString &url = QString(), const QString &displayUrl = QString(), const QString &siteName = QString(), const QString &title = QString(), const QString &description = QString(), DocumentData *doc = nullptr, PhotoData *photo = nullptr, int32 duration = 0, const QString &author = QString(), int32 pendingTill = -1); void forget() { + if (document) document->forget(); if (photo) photo->forget(); } @@ -1365,6 +1367,22 @@ struct WebPageData { }; +struct GameData { + GameData(const GameId &id, const uint64 &accessHash = 0, const QString &shortName = QString(), const QString &title = QString(), const QString &description = QString(), const QString &url = QString(), PhotoData *photo = nullptr, DocumentData *doc = nullptr); + + void forget() { + if (document) document->forget(); + if (photo) photo->forget(); + } + + GameId id; + uint64 accessHash; + QString shortName, title, description, url; + PhotoData *photo; + DocumentData *document; + +}; + QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir()); MsgId clientMsgId(); @@ -1397,70 +1415,3 @@ struct MessageCursor { inline bool operator==(const MessageCursor &a, const MessageCursor &b) { return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll); } - -struct LocationCoords { - LocationCoords() : lat(0), lon(0) { - } - LocationCoords(float64 lat, float64 lon) : lat(lat), lon(lon) { - } - LocationCoords(const MTPDgeoPoint &point) : lat(point.vlat.v), lon(point.vlong.v) { - } - float64 lat, lon; -}; -inline bool operator==(const LocationCoords &a, const LocationCoords &b) { - return (a.lat == b.lat) && (a.lon == b.lon); -} -inline bool operator<(const LocationCoords &a, const LocationCoords &b) { - return (a.lat < b.lat) || ((a.lat == b.lat) && (a.lon < b.lon)); -} -inline uint qHash(const LocationCoords &t, uint seed = 0) { -#ifndef OS_MAC_OLD - return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed); -#else // OS_MAC_OLD - uint h1 = qHash(t.lat, seed); - uint h2 = qHash(t.lon, seed); - return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed; -#endif // OS_MAC_OLD -} - -struct LocationData { - LocationData(const LocationCoords &coords) : coords(coords), loading(false) { - } - - LocationCoords coords; - ImagePtr thumb; - bool loading; - - void load(); -}; - -class LocationClickHandler : public ClickHandler { -public: - LocationClickHandler(const LocationCoords &coords) : _coords(coords) { - setup(); - } - - void onClick(Qt::MouseButton button) const override; - - QString tooltip() const override { - return QString(); - } - - QString dragText() const override { - return _text; - } - - void copyToClipboard() const override { - if (!_text.isEmpty()) { - QApplication::clipboard()->setText(_text); - } - } - QString copyToClipboardContextItemText() const override; - -private: - - void setup(); - LocationCoords _coords; - QString _text; - -}; diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp index 88212978f1..b188216877 100644 --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -218,6 +218,8 @@ '<(src_loc)/dialogs/dialogs_row.h', '<(src_loc)/history/field_autocomplete.cpp', '<(src_loc)/history/field_autocomplete.h', + '<(src_loc)/history/history_location_manager.cpp', + '<(src_loc)/history/history_location_manager.h', '<(src_loc)/history/history_service_layout.cpp', '<(src_loc)/history/history_service_layout.h', '<(src_loc)/inline_bots/inline_bot_layout_internal.cpp', From d277b0d4bba0e82c5a07eafb37ea5b48d8338dc9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 27 Sep 2016 17:20:49 +0300 Subject: [PATCH 2/6] Some parts from history module moved to history_[item,media,message]. --- Telegram/SourceFiles/app.h | 8 +- Telegram/SourceFiles/history.cpp | 6463 +---------------- Telegram/SourceFiles/history.h | 2334 +----- Telegram/SourceFiles/history/history_item.cpp | 889 +++ Telegram/SourceFiles/history/history_item.h | 935 +++ .../SourceFiles/history/history_media.cpp | 3445 +++++++++ Telegram/SourceFiles/history/history_media.h | 1057 +++ .../SourceFiles/history/history_message.cpp | 2205 ++++++ .../SourceFiles/history/history_message.h | 382 + Telegram/SourceFiles/layout.cpp | 8 + Telegram/SourceFiles/layout.h | 2 + Telegram/SourceFiles/structs.cpp | 1 - Telegram/gyp/Telegram.gyp | 6 + 13 files changed, 8939 insertions(+), 8796 deletions(-) create mode 100644 Telegram/SourceFiles/history/history_item.cpp create mode 100644 Telegram/SourceFiles/history/history_item.h create mode 100644 Telegram/SourceFiles/history/history_media.cpp create mode 100644 Telegram/SourceFiles/history/history_media.h create mode 100644 Telegram/SourceFiles/history/history_message.cpp create mode 100644 Telegram/SourceFiles/history/history_message.h diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 1f4951232d..a1e11bf735 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -21,6 +21,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "core/basic_types.h" +#include "history.h" +#include "history/history_item.h" +#include "history/history_media.h" +#include "history/history_message.h" +#include "layout.h" class AppClass; class MainWindow; @@ -28,9 +33,6 @@ class MainWidget; class ApiWrap; class FileUploader; -#include "history.h" -#include "layout.h" - using HistoryItemsMap = OrderedSet; using PhotoItems = QHash; using DocumentItems = QHash; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 2259c1e092..be1e0bdaeb 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -21,115 +21,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "history.h" -#include "core/click_handler_types.h" #include "dialogs/dialogs_indexed_list.h" #include "styles/style_dialogs.h" -#include "history/history_service_layout.h" -#include "history/history_location_manager.h" #include "data/data_drafts.h" -#include "media/media_clip_reader.h" #include "lang.h" #include "mainwidget.h" -#include "application.h" -#include "fileuploader.h" #include "mainwindow.h" -#include "ui/filedialog.h" -#include "boxes/addcontactbox.h" -#include "boxes/confirmbox.h" -#include "media/media_audio.h" #include "localstorage.h" -#include "apiwrap.h" #include "window/top_bar_widget.h" -#include "playerwidget.h" #include "observer_peer.h" -namespace { - -TextParseOptions _historySrvOptions = { - TextParseLinks | TextParseMentions | TextParseHashtags/* | TextParseMultiline*/ | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // lang-dependent -}; -TextParseOptions _webpageTitleOptions = { - TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _webpageDescriptionOptions = { - TextParseLinks | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _twitterDescriptionOptions = { - TextParseLinks | TextParseMentions | TextTwitterMentions | TextParseHashtags | TextTwitterHashtags | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _instagramDescriptionOptions = { - TextParseLinks | TextParseMentions | TextInstagramMentions | TextParseHashtags | TextInstagramHashtags | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; - -inline void _initTextOptions() { - _historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir(); - _textDlgOptions.maxw = st::dialogsWidthMax * 2; - _webpageTitleOptions.maxw = st::msgMaxWidth - st::msgPadding.left() - st::msgPadding.right() - st::webPageLeft; - _webpageTitleOptions.maxh = st::webPageTitleFont->height * 2; - _webpageDescriptionOptions.maxw = st::msgMaxWidth - st::msgPadding.left() - st::msgPadding.right() - st::webPageLeft; - _webpageDescriptionOptions.maxh = st::webPageDescriptionFont->height * 3; -} - -inline const TextParseOptions &itemTextOptions(HistoryItem *item) { - return itemTextOptions(item->history(), item->author()); -} -inline const TextParseOptions &itemTextNoMonoOptions(const HistoryItem *item) { - return itemTextNoMonoOptions(item->history(), item->author()); -} - -bool needReSetInlineResultDocument(const MTPMessageMedia &media, DocumentData *existing) { - if (media.type() == mtpc_messageMediaDocument) { - if (DocumentData *document = App::feedDocument(media.c_messageMediaDocument().vdocument)) { - if (document == existing) { - return false; - } else { - document->collectLocalData(existing); - } - } - } - return true; -} - -MediaOverviewType messageMediaToOverviewType(HistoryMedia *media) { - switch (media->type()) { - case MediaTypePhoto: return OverviewPhotos; - case MediaTypeVideo: return OverviewVideos; - case MediaTypeFile: return OverviewFiles; - case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewFiles; - case MediaTypeVoiceFile: return OverviewVoiceFiles; - case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewFiles; - default: break; - } - return OverviewCount; -} - -MediaOverviewType serviceMediaToOverviewType(HistoryMedia *media) { - switch (media->type()) { - case MediaTypePhoto: return OverviewChatPhotos; - default: break; - } - return OverviewCount; -} - -} // namespace - void historyInit() { - _initTextOptions(); + historyInitMessages(); + historyInitMedia(); } History::History(const PeerId &peerId) @@ -2221,6366 +2125,3 @@ void HistoryBlock::removeItem(HistoryItem *item) { delete this; } } - -class ReplyMarkupClickHandler : public LeftButtonClickHandler { -public: - ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) : _itemId(item->fullId()), _row(row), _col(col) { - } - - QString tooltip() const override { - return _fullDisplayed ? QString() : buttonText(); - } - - void setFullDisplayed(bool full) { - _fullDisplayed = full; - } - - // Copy to clipboard support. - void copyToClipboard() const override { - if (auto button = getButton()) { - if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) { - auto url = QString::fromUtf8(button->data); - if (!url.isEmpty()) { - QApplication::clipboard()->setText(url); - } - } - } - } - QString copyToClipboardContextItemText() const override { - if (auto button = getButton()) { - if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) { - return lang(lng_context_copy_link); - } - } - return QString(); - } - - // Finds the corresponding button in the items markup struct. - // If the button is not found it returns nullptr. - // Note: it is possible that we will point to the different button - // than the one was used when constructing the handler, but not a big deal. - const HistoryMessageReplyMarkup::Button *getButton() const { - if (auto item = App::histItemById(_itemId)) { - if (auto markup = item->Get()) { - if (_row < markup->rows.size()) { - auto &row = markup->rows.at(_row); - if (_col < row.size()) { - return &row.at(_col); - } - } - } - } - return nullptr; - } - - // We hold only FullMsgId, not HistoryItem*, because all click handlers - // are activated async and the item may be already destroyed. - void setMessageId(const FullMsgId &msgId) { - _itemId = msgId; - } - -protected: - void onClickImpl() const override { - if (auto item = App::histItemById(_itemId)) { - App::activateBotCommand(item, _row, _col); - } - } - -private: - FullMsgId _itemId; - int _row, _col; - bool _fullDisplayed = true; - - // Returns the full text of the corresponding button. - QString buttonText() const { - if (auto button = getButton()) { - return button->text; - } - return QString(); - } - -}; - -ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s) -: _item(item) -, _a_selected(animation(this, &ReplyKeyboard::step_selected)) -, _st(std_::forward(s)) { - if (auto markup = item->Get()) { - _rows.reserve(markup->rows.size()); - for (int i = 0, l = markup->rows.size(); i != l; ++i) { - auto &row = markup->rows.at(i); - int s = row.size(); - ButtonRow newRow(s, Button()); - for (int j = 0; j != s; ++j) { - auto &button = newRow[j]; - auto str = row.at(j).text; - button.type = row.at(j).type; - button.link = MakeShared(item, i, j); - button.text.setText(_st->textFont(), textOneLine(str), _textPlainOptions); - button.characters = str.isEmpty() ? 1 : str.size(); - } - _rows.push_back(newRow); - } - } -} - -void ReplyKeyboard::updateMessageId() { - auto msgId = _item->fullId(); - for_const (auto &row, _rows) { - for_const (auto &button, row) { - button.link->setMessageId(msgId); - } - } - -} - -void ReplyKeyboard::resize(int width, int height) { - _width = width; - - auto markup = _item->Get(); - float64 y = 0, buttonHeight = _rows.isEmpty() ? _st->buttonHeight() : (float64(height + _st->buttonSkip()) / _rows.size()); - for (auto &row : _rows) { - int s = row.size(); - - int widthForButtons = _width - ((s - 1) * _st->buttonSkip()); - int widthForText = widthForButtons; - int widthOfText = 0; - int maxMinButtonWidth = 0; - for_const (auto &button, row) { - widthOfText += qMax(button.text.maxWidth(), 1); - int minButtonWidth = _st->minButtonWidth(button.type); - widthForText -= minButtonWidth; - accumulate_max(maxMinButtonWidth, minButtonWidth); - } - bool exact = (widthForText == widthOfText); - bool enough = (widthForButtons - s * maxMinButtonWidth) >= widthOfText; - - float64 x = 0; - for (Button &button : row) { - int buttonw = qMax(button.text.maxWidth(), 1); - float64 textw = buttonw, minw = _st->minButtonWidth(button.type); - float64 w = textw; - if (exact) { - w += minw; - } else if (enough) { - w = (widthForButtons / float64(s)); - textw = w - minw; - } else { - textw = (widthForText / float64(s)); - w = minw + textw; - accumulate_max(w, 2 * float64(_st->buttonPadding())); - } - - int rectx = static_cast(std::floor(x)); - int rectw = static_cast(std::floor(x + w)) - rectx; - button.rect = QRect(rectx, qRound(y), rectw, qRound(buttonHeight - _st->buttonSkip())); - if (rtl()) button.rect.setX(_width - button.rect.x() - button.rect.width()); - x += w + _st->buttonSkip(); - - button.link->setFullDisplayed(textw >= buttonw); - } - y += buttonHeight; - } -} - -bool ReplyKeyboard::isEnoughSpace(int width, const style::botKeyboardButton &st) const { - for_const (auto &row, _rows) { - int s = row.size(); - int widthLeft = width - ((s - 1) * st.margin + s * 2 * st.padding); - for_const (auto &button, row) { - widthLeft -= qMax(button.text.maxWidth(), 1); - if (widthLeft < 0) { - if (row.size() > 3) { - return false; - } else { - break; - } - } - } - } - return true; -} - -void ReplyKeyboard::setStyle(StylePtr &&st) { - _st = std_::move(st); -} - -int ReplyKeyboard::naturalWidth() const { - auto result = 0; - for_const (auto &row, _rows) { - auto maxMinButtonWidth = 0; - for_const (auto &button, row) { - accumulate_max(maxMinButtonWidth, _st->minButtonWidth(button.type)); - } - auto rowMaxButtonWidth = 0; - for_const (auto &button, row) { - accumulate_max(rowMaxButtonWidth, qMax(button.text.maxWidth(), 1) + maxMinButtonWidth); - } - - auto rowSize = row.size(); - accumulate_max(result, rowSize * rowMaxButtonWidth + (rowSize - 1) * _st->buttonSkip()); - } - return result; -} - -int ReplyKeyboard::naturalHeight() const { - return (_rows.size() - 1) * _st->buttonSkip() + _rows.size() * _st->buttonHeight(); -} - -void ReplyKeyboard::paint(Painter &p, const QRect &clip) const { - t_assert(_st != nullptr); - t_assert(_width > 0); - - _st->startPaint(p); - for_const (auto &row, _rows) { - for_const (auto &button, row) { - QRect rect(button.rect); - if (rect.y() >= clip.y() + clip.height()) return; - if (rect.y() + rect.height() < clip.y()) continue; - - // just ignore the buttons that didn't layout well - if (rect.x() + rect.width() > _width) break; - - _st->paintButton(p, button); - } - } -} - -ClickHandlerPtr ReplyKeyboard::getState(int x, int y) const { - t_assert(_width > 0); - - for_const (auto &row, _rows) { - for_const (auto &button, row) { - QRect rect(button.rect); - - // just ignore the buttons that didn't layout well - if (rect.x() + rect.width() > _width) break; - - if (rect.contains(x, y)) { - return button.link; - } - } - } - return ClickHandlerPtr(); -} - -void ReplyKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (!p) return; - - bool startAnimation = false; - for (int i = 0, rows = _rows.size(); i != rows; ++i) { - auto &row = _rows.at(i); - for (int j = 0, cols = row.size(); j != cols; ++j) { - if (row.at(j).link == p) { - bool startAnimation = _animations.isEmpty(); - - int indexForAnimation = i * MatrixRowShift + j + 1; - if (!active) { - indexForAnimation = -indexForAnimation; - } - - _animations.remove(-indexForAnimation); - if (!_animations.contains(indexForAnimation)) { - _animations.insert(indexForAnimation, getms()); - } - - if (startAnimation && !_a_selected.animating()) { - _a_selected.start(); - } - return; - } - } - } -} - -void ReplyKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - _st->repaint(_item); -} - -void ReplyKeyboard::step_selected(uint64 ms, bool timer) { - for (Animations::iterator i = _animations.begin(); i != _animations.end();) { - int index = qAbs(i.key()) - 1, row = (index / MatrixRowShift), col = index % MatrixRowShift; - float64 dt = float64(ms - i.value()) / st::botKbDuration; - if (dt >= 1) { - _rows[row][col].howMuchOver = (i.key() > 0) ? 1 : 0; - i = _animations.erase(i); - } else { - _rows[row][col].howMuchOver = (i.key() > 0) ? dt : (1 - dt); - ++i; - } - } - if (timer) _st->repaint(_item); - if (_animations.isEmpty()) { - _a_selected.stop(); - } -} - -void ReplyKeyboard::clearSelection() { - for (auto i = _animations.cbegin(), e = _animations.cend(); i != e; ++i) { - int index = qAbs(i.key()) - 1, row = (index / MatrixRowShift), col = index % MatrixRowShift; - _rows[row][col].howMuchOver = 0; - } - _animations.clear(); - _a_selected.stop(); -} - -void ReplyKeyboard::Style::paintButton(Painter &p, const ReplyKeyboard::Button &button) const { - const QRect &rect = button.rect; - bool pressed = ClickHandler::showAsPressed(button.link); - - paintButtonBg(p, rect, pressed, button.howMuchOver); - paintButtonIcon(p, rect, button.type); - if (button.type == HistoryMessageReplyMarkup::Button::Type::Callback - || button.type == HistoryMessageReplyMarkup::Button::Type::Game) { - if (auto data = button.link->getButton()) { - if (data->requestId) { - paintButtonLoading(p, rect); - } - } - } - - int tx = rect.x(), tw = rect.width(); - if (tw >= st::botKbFont->elidew + _st->padding * 2) { - tx += _st->padding; - tw -= _st->padding * 2; - } else if (tw > st::botKbFont->elidew) { - tx += (tw - st::botKbFont->elidew) / 2; - tw = st::botKbFont->elidew; - } - int textTop = rect.y() + (pressed ? _st->downTextTop : _st->textTop); - button.text.drawElided(p, tx, textTop + ((rect.height() - _st->height) / 2), tw, 1, style::al_top); -} - -void HistoryMessageReplyMarkup::createFromButtonRows(const QVector &v) { - if (v.isEmpty()) { - rows.clear(); - return; - } - - rows.reserve(v.size()); - for_const (auto &row, v) { - switch (row.type()) { - case mtpc_keyboardButtonRow: { - auto &r = row.c_keyboardButtonRow(); - auto &b = r.vbuttons.c_vector().v; - if (!b.isEmpty()) { - ButtonRow buttonRow; - buttonRow.reserve(b.size()); - for_const (const auto &button, b) { - switch (button.type()) { - case mtpc_keyboardButton: { - buttonRow.push_back({ Button::Type::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 }); - } break; - case mtpc_keyboardButtonCallback: { - auto &buttonData = button.c_keyboardButtonCallback(); - buttonRow.push_back({ Button::Type::Callback, qs(buttonData.vtext), qba(buttonData.vdata), 0 }); - } break; - case mtpc_keyboardButtonRequestGeoLocation: { - buttonRow.push_back({ Button::Type::RequestLocation, qs(button.c_keyboardButtonRequestGeoLocation().vtext), QByteArray(), 0 }); - } break; - case mtpc_keyboardButtonRequestPhone: { - buttonRow.push_back({ Button::Type::RequestPhone, qs(button.c_keyboardButtonRequestPhone().vtext), QByteArray(), 0 }); - } break; - case mtpc_keyboardButtonUrl: { - auto &buttonData = button.c_keyboardButtonUrl(); - buttonRow.push_back({ Button::Type::Url, qs(buttonData.vtext), qba(buttonData.vurl), 0 }); - } break; - case mtpc_keyboardButtonSwitchInline: { - auto &buttonData = button.c_keyboardButtonSwitchInline(); - auto buttonType = buttonData.is_same_peer() ? Button::Type::SwitchInlineSame : Button::Type::SwitchInline; - buttonRow.push_back({ buttonType, qs(buttonData.vtext), qba(buttonData.vquery), 0 }); - if (buttonType == Button::Type::SwitchInline) { - // Optimization flag. - // Fast check on all new messages if there is a switch button to auto-click it. - flags |= MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button; - } - } break; - case mtpc_keyboardButtonGame: { - auto &buttonData = button.c_keyboardButtonGame(); - buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), QByteArray(), 0 }); - } break; - } - } - if (!buttonRow.isEmpty()) rows.push_back(buttonRow); - } - } break; - } - } -} - -void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) { - flags = 0; - rows.clear(); - inlineKeyboard = nullptr; - - switch (markup.type()) { - case mtpc_replyKeyboardMarkup: { - const auto &d(markup.c_replyKeyboardMarkup()); - flags = d.vflags.v; - - createFromButtonRows(d.vrows.c_vector().v); - } break; - - case mtpc_replyInlineMarkup: { - const auto &d(markup.c_replyInlineMarkup()); - flags = MTPDreplyKeyboardMarkup::Flags(0) | MTPDreplyKeyboardMarkup_ClientFlag::f_inline; - - createFromButtonRows(d.vrows.c_vector().v); - } break; - - case mtpc_replyKeyboardHide: { - const auto &d(markup.c_replyKeyboardHide()); - flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero; - } break; - - case mtpc_replyKeyboardForceReply: { - const auto &d(markup.c_replyKeyboardForceReply()); - flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply; - } break; - } -} - -ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) { - return [dependent = msgId](ChannelData *channel, MsgId msgId) { - if (HistoryItem *item = App::histItemById(dependent)) { - item->updateDependencyItem(); - } - }; -} - -void HistoryMessageUnreadBar::init(int count) { - if (_freezed) return; - _text = lng_unread_bar(lt_count, count); - _width = st::semiboldFont->width(_text); -} - -int HistoryMessageUnreadBar::height() { - return st::unreadBarHeight + st::unreadBarMargin; -} - -int HistoryMessageUnreadBar::marginTop() { - return st::lineWidth + st::unreadBarMargin; -} - -void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const { - p.fillRect(0, y + marginTop(), w, height() - marginTop() - st::lineWidth, st::unreadBarBG); - p.fillRect(0, y + height() - st::lineWidth, w, st::lineWidth, st::unreadBarBorder); - p.setFont(st::unreadBarFont); - p.setPen(st::unreadBarColor); - - int left = st::msgServiceMargin.left(); - int maxwidth = w; - if (Adaptive::Wide()) { - maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); - } - w = maxwidth; - - p.drawText((w - _width) / 2, y + marginTop() + (st::unreadBarHeight - 2 * st::lineWidth - st::unreadBarFont->height) / 2 + st::unreadBarFont->ascent, _text); -} - -void HistoryMessageDate::init(const QDateTime &date) { - _text = langDayOfMonthFull(date.date()); - _width = st::msgServiceFont->width(_text); -} - -int HistoryMessageDate::height() const { - return st::msgServiceMargin.top() + st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom() + st::msgServiceMargin.bottom(); -} - -void HistoryMessageDate::paint(Painter &p, int y, int w) const { - HistoryLayout::ServiceMessagePainter::paintDate(p, _text, _width, y, w); -} - -void HistoryMediaPtr::reset(HistoryMedia *p) { - if (_p) { - _p->detachFromParent(); - delete _p; - } - _p = p; - if (_p) { - _p->attachToParent(); - } -} - -namespace internal { - -TextSelection unshiftSelection(TextSelection selection, const Text &byText) { - if (selection == FullSelection) { - return selection; - } - return ::unshiftSelection(selection, byText); -} - -TextSelection shiftSelection(TextSelection selection, const Text &byText) { - if (selection == FullSelection) { - return selection; - } - return ::shiftSelection(selection, byText); -} - -} // namespace internal - -HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElem() -, y(0) -, id(msgId) -, date(msgDate) -, _from(from ? App::user(from) : history->peer) -, _history(history) -, _flags(flags | MTPDmessage_ClientFlag::f_pending_init_dimensions | MTPDmessage_ClientFlag::f_pending_resize) -, _authorNameVersion(author()->nameVersion) { -} - -void HistoryItem::finishCreate() { - App::historyRegItem(this); -} - -void HistoryItem::finishEdition(int oldKeyboardTop) { - setPendingInitDimensions(); - if (App::main()) { - App::main()->dlgUpdated(history(), id); - } - - // invalidate cache for drawInDialog - if (history()->textCachedFor == this) { - history()->textCachedFor = nullptr; - } - - if (oldKeyboardTop >= 0) { - if (auto keyboard = Get()) { - keyboard->oldTop = oldKeyboardTop; - } - } - - App::historyUpdateDependent(this); -} - -void HistoryItem::finishEditionToEmpty() { - recountDisplayDate(); - finishEdition(-1); - - _history->removeNotification(this); - if (history()->isChannel()) { - if (history()->peer->isMegagroup() && history()->peer->asChannel()->mgInfo->pinnedMsgId == id) { - history()->peer->asChannel()->mgInfo->pinnedMsgId = 0; - } - } - if (history()->lastKeyboardId == id) { - history()->clearLastKeyboard(); - } - if ((!out() || isPost()) && unread() && history()->unreadCount() > 0) { - history()->setUnreadCount(history()->unreadCount() - 1); - } - - if (auto next = nextItem()) { - next->previousItemChanged(); - } -} - -void HistoryItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (auto markup = Get()) { - if (markup->inlineKeyboard) { - markup->inlineKeyboard->clickHandlerActiveChanged(p, active); - } - } - App::hoveredLinkItem(active ? this : nullptr); - Ui::repaintHistoryItem(this); -} - -void HistoryItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - if (auto markup = Get()) { - if (markup->inlineKeyboard) { - markup->inlineKeyboard->clickHandlerPressedChanged(p, pressed); - } - } - App::pressedLinkItem(pressed ? this : nullptr); - Ui::repaintHistoryItem(this); -} - -void HistoryItem::destroy() { - // All this must be done for all items manually in History::clear(false)! - eraseFromOverview(); - - bool wasAtBottom = history()->loadedAtBottom(); - _history->removeNotification(this); - detach(); - if (history()->isChannel()) { - if (history()->peer->isMegagroup() && history()->peer->asChannel()->mgInfo->pinnedMsgId == id) { - history()->peer->asChannel()->mgInfo->pinnedMsgId = 0; - } - } - if (history()->lastMsg == this) { - history()->fixLastMessage(wasAtBottom); - } - if (history()->lastKeyboardId == id) { - history()->clearLastKeyboard(); - } - if ((!out() || isPost()) && unread() && history()->unreadCount() > 0) { - history()->setUnreadCount(history()->unreadCount() - 1); - } - Global::RefPendingRepaintItems().remove(this); - delete this; -} - -void HistoryItem::detach() { - if (detached()) return; - - if (_history->isChannel()) { - _history->asChannelHistory()->messageDetached(this); - } - _block->removeItem(this); - App::historyItemDetached(this); - - _history->setPendingResize(); -} - -void HistoryItem::detachFast() { - _block = nullptr; - _indexInBlock = -1; -} - -void HistoryItem::previousItemChanged() { - recountDisplayDate(); - recountAttachToPrevious(); -} - -void HistoryItem::recountAttachToPrevious() { - bool attach = false; - if (!isPost() && !Has() && !Has()) { - if (auto previos = previousItem()) { - attach = !previos->isPost() - && !previos->serviceMsg() - && !previos->isEmpty() - && previos->from() == from() - && (qAbs(previos->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta); - } - } - if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { - _flags |= MTPDmessage_ClientFlag::f_attach_to_previous; - setPendingInitDimensions(); - } else if (!attach && (_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { - _flags &= ~MTPDmessage_ClientFlag::f_attach_to_previous; - setPendingInitDimensions(); - } -} - -void HistoryItem::setId(MsgId newId) { - history()->changeMsgId(id, newId); - id = newId; - - // We don't need to call Notify::replyMarkupUpdated(this) and update keyboard - // in history widget, because it can't exist for an outgoing message. - // Only inline keyboards can be in outgoing messages. - if (auto markup = inlineReplyMarkup()) { - if (markup->inlineKeyboard) { - markup->inlineKeyboard->updateMessageId(); - } - } -} - -bool HistoryItem::canEdit(const QDateTime &cur) const { - auto messageToMyself = (peerToUser(_history->peer->id) == MTP::authedId()); - auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit()); - if (id < 0 || messageTooOld) return false; - - if (auto msg = toHistoryMessage()) { - if (msg->Has() || msg->Has()) return false; - - if (auto media = msg->getMedia()) { - auto type = media->type(); - if (type != MediaTypePhoto && - type != MediaTypeVideo && - type != MediaTypeFile && - type != MediaTypeGif && - type != MediaTypeMusicFile && - type != MediaTypeVoiceFile && - type != MediaTypeWebPage) { - return false; - } - } - if (isPost()) { - auto channel = _history->peer->asChannel(); - return (channel->amCreator() || (channel->amEditor() && out())); - } - return out() || messageToMyself; - } - return false; -} - -bool HistoryItem::unread() const { - // Messages from myself are always read. - if (history()->peer->isSelf()) return false; - - if (out()) { - // Outgoing messages in converted chats are always read. - if (history()->peer->migrateTo()) return false; - - if (id > 0) { - if (id < history()->outboxReadBefore) return false; - if (auto user = history()->peer->asUser()) { - if (user->botInfo) return false; - } else if (auto channel = history()->peer->asChannel()) { - if (!channel->isMegagroup()) return false; - } - } - return true; - } - - if (id > 0) { - if (id < history()->inboxReadBefore) return false; - return true; - } - return (_flags & MTPDmessage_ClientFlag::f_clientside_unread); -} - -void HistoryItem::destroyUnreadBar() { - if (Has()) { - RemoveComponents(HistoryMessageUnreadBar::Bit()); - setPendingInitDimensions(); - if (_history->unreadBar == this) { - _history->unreadBar = nullptr; - } - - recountAttachToPrevious(); - } -} - -void HistoryItem::setUnreadBarCount(int count) { - if (count > 0) { - HistoryMessageUnreadBar *bar; - if (!Has()) { - AddComponents(HistoryMessageUnreadBar::Bit()); - setPendingInitDimensions(); - - recountAttachToPrevious(); - - bar = Get(); - } else { - bar = Get(); - if (bar->_freezed) { - return; - } - Global::RefPendingRepaintItems().insert(this); - } - bar->init(count); - } else { - destroyUnreadBar(); - } -} - -void HistoryItem::setUnreadBarFreezed() { - if (auto bar = Get()) { - bar->_freezed = true; - } -} - -void HistoryItem::clipCallback(Media::Clip::Notification notification) { - using namespace Media::Clip; - - HistoryMedia *media = getMedia(); - if (!media) return; - - Reader *reader = media ? media->getClipReader() : 0; - if (!reader) return; - - switch (notification) { - case NotificationReinit: { - bool stopped = false; - if (reader->autoPausedGif()) { - if (MainWidget *m = App::main()) { - if (!m->isItemVisible(this)) { // stop animation if it is not visible - media->stopInline(); - if (DocumentData *document = media->getDocument()) { // forget data from memory - document->forget(); - } - stopped = true; - } - } - } - if (!stopped) { - setPendingInitDimensions(); - Notify::historyItemLayoutChanged(this); - } - } break; - - case NotificationRepaint: { - if (!reader->currentDisplayed()) { - Ui::repaintHistoryItem(this); - } - } break; - } -} - -void HistoryItem::recountDisplayDate() { - bool displayingDate = ([this]() { - if (isEmpty()) return false; - - if (auto previous = previousItem()) { - return previous->isEmpty() || (previous->date.date() != date.date()); - } - return true; - })(); - - if (displayingDate && !Has()) { - AddComponents(HistoryMessageDate::Bit()); - Get()->init(date); - setPendingInitDimensions(); - } else if (!displayingDate && Has()) { - RemoveComponents(HistoryMessageDate::Bit()); - setPendingInitDimensions(); - } -} - -QString HistoryItem::notificationText() const { - auto getText = [this]() { - if (emptyText()) { - return _media ? _media->notificationText() : QString(); - } - return _text.originalText(); - }; - - auto result = getText(); - if (result.size() > 0xFF) result = result.mid(0, 0xFF) + qsl("..."); - return result; -} - -QString HistoryItem::inDialogsText() const { - auto getText = [this]() { - if (emptyText()) { - return _media ? _media->inDialogsText() : QString(); - } - return textClean(_text.originalText()); - }; - auto plainText = getText(); - if ((!_history->peer->isUser() || out()) && !isPost() && !isEmpty()) { - auto fromText = author()->isSelf() ? lang(lng_from_you) : author()->shortName(); - auto fromWrapped = textcmdLink(1, lng_dialogs_text_from_wrapped(lt_from, textClean(fromText))); - return lng_dialogs_text_with_from(lt_from_part, fromWrapped, lt_message, plainText); - } - return plainText; -} - -void HistoryItem::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { - if (cacheFor != this) { - cacheFor = this; - cache.setText(st::dialogsTextFont, inDialogsText(), _textDlgOptions); - } - if (r.width()) { - textstyleSet(&(act ? st::dialogsTextStyleActive : st::dialogsTextStyle)); - p.setFont(st::dialogsTextFont); - p.setPen(act ? st::dialogsTextFgActive : st::dialogsTextFg); - cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dialogsTextFont->height); - textstyleRestore(); - } -} - -HistoryItem::~HistoryItem() { - App::historyUnregItem(this); - if (id < 0 && App::uploader()) { - App::uploader()->cancel(fullId()); - } -} - -RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks) -: _firstStart(0) -, _lastStart(0) -, _lastTime(0) -, _opacity(0) -, a_arcEnd(0, 0) -, a_arcStart(0, FullArcLength) -, _animation(std_::move(callbacks)) { - -} - -void RadialAnimation::start(float64 prg) { - _firstStart = _lastStart = _lastTime = getms(); - int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength), iprgstrict = qRound(prg * AlmostFullArcLength); - a_arcEnd = anim::ivalue(iprgstrict, iprg); - _animation.start(); -} - -void RadialAnimation::update(float64 prg, bool finished, uint64 ms) { - int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength); - if (iprg != a_arcEnd.to()) { - a_arcEnd.start(iprg); - _lastStart = _lastTime; - } - _lastTime = ms; - - float64 dt = float64(ms - _lastStart), fulldt = float64(ms - _firstStart); - _opacity = qMin(fulldt / st::radialDuration, 1.); - if (!finished) { - a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear); - } else if (dt >= st::radialDuration) { - a_arcEnd.update(1, anim::linear); - stop(); - } else { - float64 r = dt / st::radialDuration; - a_arcEnd.update(r, anim::linear); - _opacity *= 1 - r; - } - float64 fromstart = fulldt / st::radialPeriod; - a_arcStart.update(fromstart - std::floor(fromstart), anim::linear); -} - -void RadialAnimation::stop() { - _firstStart = _lastStart = _lastTime = 0; - a_arcEnd = anim::ivalue(0, 0); - _animation.stop(); -} - -void RadialAnimation::step(uint64 ms) { - _animation.step(ms); -} - -void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color) { - float64 o = p.opacity(); - p.setOpacity(o * _opacity); - - QPen pen(color->p), was(p.pen()); - pen.setWidth(thickness); - p.setPen(pen); - - int32 len = MinArcLength + a_arcEnd.current(); - int32 from = QuarterArcLength - a_arcStart.current() - len; - if (rtl()) { - from = QuarterArcLength - (from - QuarterArcLength) - len; - if (from < 0) from += FullArcLength; - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawArc(inner, from, len); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setPen(was); - p.setOpacity(o); -} - -QString HistoryMedia::inDialogsText() const { - auto result = notificationText(); - return result.isEmpty() ? QString() : textcmdLink(1, textClean(result)); -} - -namespace { - -int32 documentMaxStatusWidth(DocumentData *document) { - int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); - if (SongData *song = document->song()) { - result = qMax(result, st::normalFont->width(formatPlayedText(song->duration, song->duration))); - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(song->duration, document->size))); - } else if (VoiceData *voice = document->voice()) { - result = qMax(result, st::normalFont->width(formatPlayedText(voice->duration, voice->duration))); - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(voice->duration, document->size))); - } else if (document->isVideo()) { - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(document->duration(), document->size))); - } else { - result = qMax(result, st::normalFont->width(formatSizeText(document->size))); - } - return result; -} - -int32 gifMaxStatusWidth(DocumentData *document) { - int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); - result = qMax(result, st::normalFont->width(formatGifAndSizeText(document->size))); - return result; -} - -TextWithEntities captionedSelectedText(const QString &attachType, const Text &caption, TextSelection selection) { - if (selection != FullSelection) { - return caption.originalTextWithEntities(selection, ExpandLinksAll); - } - - TextWithEntities result, original; - if (!caption.isEmpty()) { - original = caption.originalTextWithEntities(AllTextSelection, ExpandLinksAll); - } - result.text.reserve(5 + attachType.size() + original.text.size()); - result.text.append(qstr("[ ")).append(attachType).append(qstr(" ]")); - if (!caption.isEmpty()) { - result.text.append(qstr("\n")); - appendTextWithEntities(result, std_::move(original)); - } - return result; -} - -QString captionedNotificationText(const QString &attachType, const Text &caption) { - if (caption.isEmpty()) { - return attachType; - } - - auto captionText = caption.originalText(); - auto attachTypeWrapped = lng_dialogs_text_media_wrapped(lt_media, attachType); - return lng_dialogs_text_media(lt_media_part, attachTypeWrapped, lt_caption, captionText); -} - -QString captionedInDialogsText(const QString &attachType, const Text &caption) { - if (caption.isEmpty()) { - return textcmdLink(1, textClean(attachType)); - } - - auto captionText = textClean(caption.originalText()); - auto attachTypeWrapped = textcmdLink(1, lng_dialogs_text_media_wrapped(lt_media, textClean(attachType))); - return lng_dialogs_text_media(lt_media_part, attachTypeWrapped, lt_caption, captionText); -} - -} // namespace - -void HistoryFileMedia::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (p == _savel || p == _cancell) { - if (active && !dataLoaded()) { - ensureAnimation(); - _animation->a_thumbOver.start(1); - _animation->_a_thumbOver.start(); - } else if (!active && _animation) { - _animation->a_thumbOver.start(0); - _animation->_a_thumbOver.start(); - } - } -} - -void HistoryFileMedia::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - Ui::repaintHistoryItem(_parent); -} - -void HistoryFileMedia::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell) { - _openl = std_::move(openl); - _savel = std_::move(savel); - _cancell = std_::move(cancell); -} - -void HistoryFileMedia::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const { - _statusSize = newSize; - if (_statusSize == FileStatusSizeReady) { - _statusText = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize)); - } else if (_statusSize == FileStatusSizeLoaded) { - _statusText = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize)); - } else if (_statusSize == FileStatusSizeFailed) { - _statusText = lang(lng_attach_failed); - } else if (_statusSize >= 0) { - _statusText = formatDownloadText(_statusSize, fullSize); - } else { - _statusText = formatPlayedText(-_statusSize - 1, realDuration); - } -} - -void HistoryFileMedia::step_thumbOver(float64 ms, bool timer) { - float64 dt = ms / st::msgFileOverDuration; - if (dt >= 1) { - _animation->a_thumbOver.finish(); - _animation->_a_thumbOver.stop(); - checkAnimationFinished(); - } else if (!timer) { - _animation->a_thumbOver.update(dt, anim::linear); - } - if (timer) { - Ui::repaintHistoryItem(_parent); - } -} - -void HistoryFileMedia::step_radial(uint64 ms, bool timer) { - if (timer) { - Ui::repaintHistoryItem(_parent); - } else { - _animation->radial.update(dataProgress(), dataFinished(), ms); - if (!_animation->radial.animating()) { - checkAnimationFinished(); - } - } -} - -void HistoryFileMedia::ensureAnimation() const { - if (!_animation) { - _animation = new AnimationData( - animation(const_cast(this), &HistoryFileMedia::step_thumbOver), - animation(const_cast(this), &HistoryFileMedia::step_radial)); - } -} - -void HistoryFileMedia::checkAnimationFinished() { - if (_animation && !_animation->_a_thumbOver.animating() && !_animation->radial.animating()) { - if (dataLoaded()) { - delete _animation; - _animation = 0; - } - } -} - -HistoryFileMedia::~HistoryFileMedia() { - deleteAndMark(_animation); -} - -HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent) -, _data(photo) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { - setLinks(MakeShared(_data), MakeShared(_data), MakeShared(_data)); - if (!caption.isEmpty()) { - _caption.setText(st::msgFont, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent)); - } - init(); -} - -HistoryPhoto::HistoryPhoto(HistoryItem *parent, PeerData *chat, const MTPDphoto &photo, int32 width) : HistoryFileMedia(parent) -, _data(App::feedPhoto(photo)) { - setLinks(MakeShared(_data, chat), MakeShared(_data, chat), MakeShared(_data, chat)); - - _width = width; - init(); -} - -HistoryPhoto::HistoryPhoto(HistoryItem *parent, const HistoryPhoto &other) : HistoryFileMedia(parent) -, _data(other._data) -, _pixw(other._pixw) -, _pixh(other._pixh) -, _caption(other._caption) { - setLinks(MakeShared(_data), MakeShared(_data), MakeShared(_data)); - - init(); -} - -void HistoryPhoto::init() { - _data->thumb->load(); -} - -void HistoryPhoto::initDimensions() { - if (_caption.hasSkipBlock()) { - _caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); - } - - int32 tw = convertScale(_data->full->width()), th = convertScale(_data->full->height()); - if (!tw || !th) { - tw = th = 1; - } - if (tw > st::maxMediaSize) { - th = (st::maxMediaSize * th) / tw; - tw = st::maxMediaSize; - } - if (th > st::maxMediaSize) { - tw = (st::maxMediaSize * tw) / th; - th = st::maxMediaSize; - } - - if (_parent->toHistoryMessage()) { - bool bubble = _parent->hasBubble(); - - int32 minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - int32 maxActualWidth = qMax(tw, minWidth); - _maxw = qMax(maxActualWidth, th); - _minh = qMax(th, int32(st::minPhotoSize)); - if (bubble) { - maxActualWidth += st::mediaPadding.left() + st::mediaPadding.right(); - _maxw += st::mediaPadding.left() + st::mediaPadding.right(); - _minh += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - _minh += st::mediaCaptionSkip + _caption.countHeight(maxActualWidth - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } - } - } else { - _maxw = _minh = _width; - } -} - -int HistoryPhoto::resizeGetHeight(int width) { - bool bubble = _parent->hasBubble(); - - int tw = convertScale(_data->full->width()), th = convertScale(_data->full->height()); - if (tw > st::maxMediaSize) { - th = (st::maxMediaSize * th) / tw; - tw = st::maxMediaSize; - } - if (th > st::maxMediaSize) { - tw = (st::maxMediaSize * tw) / th; - th = st::maxMediaSize; - } - - _pixw = qMin(width, _maxw); - if (bubble) { - _pixw -= st::mediaPadding.left() + st::mediaPadding.right(); - } - _pixh = th; - if (tw > _pixw) { - _pixh = (_pixw * _pixh / tw); - } else { - _pixw = tw; - } - if (_pixh > width) { - _pixw = (_pixw * width) / _pixh; - _pixh = width; - } - if (_pixw < 1) _pixw = 1; - if (_pixh < 1) _pixh = 1; - - int minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - _width = qMax(_pixw, int16(minWidth)); - _height = qMax(_pixh, int16(st::minPhotoSize)); - if (bubble) { - _width += st::mediaPadding.left() + st::mediaPadding.right(); - _height += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - int captionw = _width - st::msgPadding.left() - st::msgPadding.right(); - _height += st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); - } - } - return _height; -} - -void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - p.fillRect(QRect(0, 0, _width, _height), QColor(128, 255, 128)); - - _data->automaticLoad(_parent); - bool selected = (selection == FullSelection); - bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); - - bool notChild = (_parent->getMedia() == this); - int skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - - int captionw = width - st::msgPadding.left() - st::msgPadding.right(); - - if (displayLoading) { - ensureAnimation(); - if (!_animation->radial.animating()) { - _animation->radial.start(_data->progress()); - } - } - bool radial = isRadialAnimation(ms); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); - } - } else { - App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); - } - - auto inWebPage = (_parent->getMedia() != this); - auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; - QPixmap pix; - if (loaded) { - pix = _data->full->pixSingle(roundRadius, _pixw, _pixh, width, height); - } else { - pix = _data->thumb->pixBlurredSingle(roundRadius, _pixw, _pixh, width, height); - } - QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); - p.drawPixmap(rthumb.topLeft(), pix); - if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); - } - - if (notChild && (radial || (!loaded && !_data->loading()))) { - float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _animation->radial.opacity() : 1; - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgDateImgBgSelected); - } else if (isThumbAnimation(ms)) { - float64 over = _animation->a_thumbOver.current(); - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); - } - - p.setOpacity(radialOpacity * p.opacity()); - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity(radial ? _animation->radial.opacity() : 1); - - p.setOpacity(radialOpacity); - style::sprite icon; - if (radial || _data->loading()) { - DelayedStorageImage *delayed = _data->full->toDelayedStorageImage(); - if (!delayed || !delayed->location().isNull()) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - if (!icon.isEmpty()) { - p.drawSpriteCenter(inner, icon); - } - if (radial) { - p.setOpacity(1); - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - } - - // date - if (_caption.isEmpty()) { - if (notChild && (_data->uploading() || App::hoveredItem() == _parent)) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); - } - } else { - p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); - } -} - -HistoryTextState HistoryPhoto::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - int skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - if (!_caption.isEmpty()) { - int captionw = width - st::msgPadding.left() - st::msgPadding.right(); - height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); - if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); - return result; - } - height -= st::mediaCaptionSkip; - } - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - } - if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { - if (_data->uploading()) { - result.link = _cancell; - } else if (_data->loaded()) { - result.link = _openl; - } else if (_data->loading()) { - DelayedStorageImage *delayed = _data->full->toDelayedStorageImage(); - if (!delayed || !delayed->location().isNull()) { - result.link = _cancell; - } - } else { - result.link = _savel; - } - if (_caption.isEmpty() && _parent->getMedia() == this) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } - return result; - } - return result; -} - -void HistoryPhoto::updateSentMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaPhoto) { - auto &photo = media.c_messageMediaPhoto().vphoto; - App::feedPhoto(photo, _data); - - if (photo.type() == mtpc_photo) { - auto &sizes = photo.c_photo().vsizes.c_vector().v; - int32 max = 0; - const MTPDfileLocation *maxLocation = 0; - for (int32 i = 0, l = sizes.size(); i < l; ++i) { - char size = 0; - const MTPFileLocation *loc = 0; - switch (sizes.at(i).type()) { - case mtpc_photoSize: { - const string &s(sizes.at(i).c_photoSize().vtype.c_string().v); - loc = &sizes.at(i).c_photoSize().vlocation; - if (s.size()) size = s[0]; - } break; - - case mtpc_photoCachedSize: { - const string &s(sizes.at(i).c_photoCachedSize().vtype.c_string().v); - loc = &sizes.at(i).c_photoCachedSize().vlocation; - if (s.size()) size = s[0]; - } break; - } - if (!loc || loc->type() != mtpc_fileLocation) continue; - if (size == 's') { - Local::writeImage(storageKey(loc->c_fileLocation()), _data->thumb); - } else if (size == 'm') { - Local::writeImage(storageKey(loc->c_fileLocation()), _data->medium); - } else if (size == 'x' && max < 1) { - max = 1; - maxLocation = &loc->c_fileLocation(); - } else if (size == 'y' && max < 2) { - max = 2; - maxLocation = &loc->c_fileLocation(); - //} else if (size == 'w' && max < 3) { - // max = 3; - // maxLocation = &loc->c_fileLocation(); - } - } - if (maxLocation) { - Local::writeImage(storageKey(*maxLocation), _data->full); - } - } - } -} - -bool HistoryPhoto::needReSetInlineResultMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaPhoto) { - if (PhotoData *existing = App::feedPhoto(media.c_messageMediaPhoto().vphoto)) { - if (existing == _data) { - return false; - } else { - // collect data - } - } - } - return false; -} - -void HistoryPhoto::attachToParent() { - App::regPhotoItem(_data, _parent); -} - -void HistoryPhoto::detachFromParent() { - App::unregPhotoItem(_data, _parent); -} - -QString HistoryPhoto::notificationText() const { - return captionedNotificationText(lang(lng_in_dlg_photo), _caption); -} - -QString HistoryPhoto::inDialogsText() const { - return captionedInDialogsText(lang(lng_in_dlg_photo), _caption); -} - -TextWithEntities HistoryPhoto::selectedText(TextSelection selection) const { - return captionedSelectedText(lang(lng_in_dlg_photo), _caption, selection); -} - -ImagePtr HistoryPhoto::replyPreview() { - return _data->makeReplyPreview(); -} - -HistoryVideo::HistoryVideo(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent) -, _data(document) -, _thumbw(1) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { - if (!caption.isEmpty()) { - _caption.setText(st::msgFont, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent)); - } - - setDocumentLinks(_data); - - setStatusSize(FileStatusSizeReady); - - _data->thumb->load(); -} - -HistoryVideo::HistoryVideo(HistoryItem *parent, const HistoryVideo &other) : HistoryFileMedia(parent) -, _data(other._data) -, _thumbw(other._thumbw) -, _caption(other._caption) { - setDocumentLinks(_data); - - setStatusSize(other._statusSize); -} - -void HistoryVideo::initDimensions() { - bool bubble = _parent->hasBubble(); - - if (_caption.hasSkipBlock()) { - _caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); - } - - int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); - if (!tw || !th) { - tw = th = 1; - } - if (tw * st::msgVideoSize.height() > th * st::msgVideoSize.width()) { - th = qRound((st::msgVideoSize.width() / float64(tw)) * th); - tw = st::msgVideoSize.width(); - } else { - tw = qRound((st::msgVideoSize.height() / float64(th)) * tw); - th = st::msgVideoSize.height(); - } - - _thumbw = qMax(tw, 1); - int32 minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - minWidth = qMax(minWidth, documentMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - _maxw = qMax(_thumbw, int32(minWidth)); - _minh = qMax(th, int32(st::minPhotoSize)); - if (bubble) { - _maxw += st::mediaPadding.left() + st::mediaPadding.right(); - _minh += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - _minh += st::mediaCaptionSkip + _caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } - } -} - -int HistoryVideo::resizeGetHeight(int width) { - bool bubble = _parent->hasBubble(); - - int tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); - if (!tw || !th) { - tw = th = 1; - } - if (tw * st::msgVideoSize.height() > th * st::msgVideoSize.width()) { - th = qRound((st::msgVideoSize.width() / float64(tw)) * th); - tw = st::msgVideoSize.width(); - } else { - tw = qRound((st::msgVideoSize.height() / float64(th)) * tw); - th = st::msgVideoSize.height(); - } - - if (bubble) { - width -= st::mediaPadding.left() + st::mediaPadding.right(); - } - if (width < tw) { - th = qRound((width / float64(tw)) * th); - tw = width; - } - - _thumbw = qMax(tw, 1); - int minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - minWidth = qMax(minWidth, documentMaxStatusWidth(_data) + 2 * int(st::msgDateImgDelta + st::msgDateImgPadding.x())); - _width = qMax(_thumbw, int(minWidth)); - _height = qMax(th, int(st::minPhotoSize)); - if (bubble) { - _width += st::mediaPadding.left() + st::mediaPadding.right(); - _height += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - int captionw = _width - st::msgPadding.left() - st::msgPadding.right(); - _height += st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); - } - } - return _height; -} - -void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - - _data->automaticLoad(_parent); - bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); - bool selected = (selection == FullSelection); - - int skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - - int captionw = width - st::msgPadding.left() - st::msgPadding.right(); - - if (displayLoading) { - ensureAnimation(); - if (!_animation->radial.animating()) { - _animation->radial.start(_data->progress()); - } - } - updateStatusText(); - bool radial = isRadialAnimation(ms); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); - } - } else { - App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); - } - - QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); - p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(ImageRoundRadius::Large, _thumbw, 0, width, height)); - if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); - } - - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgDateImgBgSelected); - } else if (isThumbAnimation(ms)) { - float64 over = _animation->a_thumbOver.current(); - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - if (!selected && _animation) { - p.setOpacity(1); - } - - style::sprite icon; - if (loaded) { - icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); - } else if (radial || _data->loading()) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - p.drawSpriteCenter(inner, icon); - if (radial) { - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - - int32 statusX = skipx + st::msgDateImgDelta + st::msgDateImgPadding.x(), statusY = skipy + st::msgDateImgDelta + st::msgDateImgPadding.y(); - int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); - int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); - App::roundRect(p, rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); - p.setFont(st::normalFont); - p.setPen(st::white); - p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x()); - - // date - if (_caption.isEmpty()) { - if (_parent->getMedia() == this) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); - } - } else { - p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); - } -} - -HistoryTextState HistoryVideo::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - - bool loaded = _data->loaded(); - - int32 skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - if (!_caption.isEmpty()) { - int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); - height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); - if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); - } - height -= st::mediaCaptionSkip; - } - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - } - if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { - result.link = loaded ? _openl : (_data->loading() ? _cancell : _savel); - if (_caption.isEmpty() && _parent->getMedia() == this) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } - return result; - } - return result; -} - -void HistoryVideo::setStatusSize(int32 newSize) const { - HistoryFileMedia::setStatusSize(newSize, _data->size, _data->duration(), 0); -} - -QString HistoryVideo::notificationText() const { - return captionedNotificationText(lang(lng_in_dlg_video), _caption); -} - -QString HistoryVideo::inDialogsText() const { - return captionedInDialogsText(lang(lng_in_dlg_video), _caption); -} - -TextWithEntities HistoryVideo::selectedText(TextSelection selection) const { - return captionedSelectedText(lang(lng_in_dlg_video), _caption, selection); -} - -void HistoryVideo::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0, realDuration = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->status == FileUploading) { - statusSize = _data->uploadOffset; - } else if (_data->loading()) { - statusSize = _data->loadOffset(); - } else if (_data->loaded()) { - statusSize = FileStatusSizeLoaded; - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - setStatusSize(statusSize); - } -} - -void HistoryVideo::attachToParent() { - App::regDocumentItem(_data, _parent); -} - -void HistoryVideo::detachFromParent() { - App::unregDocumentItem(_data, _parent); -} - -bool HistoryVideo::needReSetInlineResultMedia(const MTPMessageMedia &media) { - return needReSetInlineResultDocument(media, _data); -} - -ImagePtr HistoryVideo::replyPreview() { - if (_data->replyPreview->isNull() && !_data->thumb->isNull()) { - if (_data->thumb->loaded()) { - int w = convertScale(_data->thumb->width()), h = convertScale(_data->thumb->height()); - if (w <= 0) w = 1; - if (h <= 0) h = 1; - _data->replyPreview = ImagePtr(w > h ? _data->thumb->pix(w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : _data->thumb->pix(st::msgReplyBarSize.height()), "PNG"); - } else { - _data->thumb->load(); - } - } - return _data->replyPreview; -} - -HistoryDocumentVoicePlayback::HistoryDocumentVoicePlayback(const HistoryDocument *that) -: _position(0) -, a_progress(0., 0.) -, _a_progress(animation(const_cast(that), &HistoryDocument::step_voiceProgress)) { -} - -void HistoryDocumentVoice::ensurePlayback(const HistoryDocument *that) const { - if (!_playback) { - _playback = new HistoryDocumentVoicePlayback(that); - } -} - -void HistoryDocumentVoice::checkPlaybackFinished() const { - if (_playback && !_playback->_a_progress.animating()) { - delete _playback; - _playback = nullptr; - } -} - -HistoryDocument::HistoryDocument(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent) -, _data(document) { - createComponents(!caption.isEmpty()); - if (auto named = Get()) { - named->_name = documentName(_data); - named->_namew = st::semiboldFont->width(named->_name); - } - - setDocumentLinks(_data); - - setStatusSize(FileStatusSizeReady); - - if (auto captioned = Get()) { - captioned->_caption.setText(st::msgFont, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent)); - } -} - -HistoryDocument::HistoryDocument(HistoryItem *parent, const HistoryDocument &other) : HistoryFileMedia(parent) -, Composer() -, _data(other._data) { - auto captioned = other.Get(); - createComponents(captioned != 0); - if (auto named = Get()) { - if (auto othernamed = other.Get()) { - named->_name = othernamed->_name; - named->_namew = othernamed->_namew; - } else { - named->_name = documentName(_data); - named->_namew = st::semiboldFont->width(named->_name); - } - } - - setDocumentLinks(_data); - - setStatusSize(other._statusSize); - - if (captioned) { - Get()->_caption = captioned->_caption; - } -} - -void HistoryDocument::createComponents(bool caption) { - uint64 mask = 0; - if (_data->voice()) { - mask |= HistoryDocumentVoice::Bit(); - } else { - mask |= HistoryDocumentNamed::Bit(); - if (!_data->song() && !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height()) { - mask |= HistoryDocumentThumbed::Bit(); - } - } - if (caption) { - mask |= HistoryDocumentCaptioned::Bit(); - } - UpdateComponents(mask); - if (auto thumbed = Get()) { - thumbed->_linksavel.reset(new DocumentSaveClickHandler(_data)); - thumbed->_linkcancell.reset(new DocumentCancelClickHandler(_data)); - } -} - -void HistoryDocument::initDimensions() { - auto captioned = Get(); - if (captioned && captioned->_caption.hasSkipBlock()) { - captioned->_caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); - } - - auto thumbed = Get(); - if (thumbed) { - _data->thumb->load(); - int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); - if (tw > th) { - thumbed->_thumbw = (tw * st::msgFileThumbSize) / th; - } else { - thumbed->_thumbw = st::msgFileThumbSize; - } - } - - _maxw = st::msgFileMinWidth; - - int32 tleft = 0, tright = 0; - if (thumbed) { - tleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - tright = st::msgFileThumbPadding.left(); - _maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + tright); - } else { - tleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - tright = st::msgFileThumbPadding.left(); - int32 unread = _data->voice() ? (st::mediaUnreadSkip + st::mediaUnreadSize) : 0; - _maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + unread + _parent->skipBlockWidth() + st::msgPadding.right()); - } - - if (auto named = Get()) { - _maxw = qMax(tleft + named->_namew + tright, _maxw); - _maxw = qMin(_maxw, int(st::msgMaxWidth)); - } - - if (thumbed) { - _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - if (!captioned && _parent->Has()) { - _minh += st::msgDateFont->height - st::msgDateDelta.y(); - } - } else { - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - } - - if (captioned) { - _minh += captioned->_caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } else { - _height = _minh; - } -} - -int HistoryDocument::resizeGetHeight(int width) { - auto captioned = Get(); - if (!captioned) { - return HistoryFileMedia::resizeGetHeight(width); - } - - _width = qMin(width, _maxw); - if (Get()) { - _height = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - } else { - _height = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - } - _height += captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - - return _height; -} - -void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - - _data->automaticLoad(_parent); - bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); - bool selected = (selection == FullSelection); - - int captionw = _width - st::msgPadding.left() - st::msgPadding.right(); - - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - - if (displayLoading) { - ensureAnimation(); - if (!_animation->radial.animating()) { - _animation->radial.start(_data->progress()); - } - } - bool showPause = updateStatusText(); - bool radial = isRadialAnimation(ms); - - int nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0; - if (auto thumbed = Get()) { - nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - nametop = st::msgFileThumbNameTop; - nameright = st::msgFileThumbPadding.left(); - statustop = st::msgFileThumbStatusTop; - linktop = st::msgFileThumbLinkTop; - bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - - QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); - QPixmap thumb = loaded ? _data->thumb->pixSingle(ImageRoundRadius::Large, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); - p.drawPixmap(rthumb.topLeft(), thumb); - if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); - } - - if (radial || (!loaded && !_data->loading())) { - float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _animation->radial.opacity() : 1; - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgDateImgBgSelected); - } else if (isThumbAnimation(ms)) { - float64 over = _animation->a_thumbOver.current(); - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); - } - p.setOpacity(radialOpacity * p.opacity()); - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity(radialOpacity); - style::sprite icon; - if (radial || _data->loading()) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - p.setOpacity((radial && loaded) ? _animation->radial.opacity() : 1); - p.drawSpriteCenter(inner, icon); - if (radial) { - p.setOpacity(1); - - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - } - - if (_data->status != FileUploadFailed) { - const ClickHandlerPtr &lnk((_data->loading() || _data->status == FileUploading) ? thumbed->_linkcancell : thumbed->_linksavel); - bool over = ClickHandler::showAsActive(lnk); - p.setFont(over ? st::semiboldFont->underline() : st::semiboldFont); - p.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg)); - p.drawTextLeft(nameleft, linktop, _width, thumbed->_link, thumbed->_linkw); - } - } else { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nametop = st::msgFileNameTop; - nameright = st::msgFilePadding.left(); - statustop = st::msgFileStatusTop; - bottom = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected); - } else if (isThumbAnimation(ms)) { - float64 over = _animation->a_thumbOver.current(); - p.setBrush(style::interpolate(outbg ? st::msgFileOutBg : st::msgFileInBg, outbg ? st::msgFileOutBgOver : st::msgFileInBgOver, over)); - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(outbg ? (over ? st::msgFileOutBgOver : st::msgFileOutBg) : (over ? st::msgFileInBgOver : st::msgFileInBg)); - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - if (radial) { - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg)); - _animation->radial.draw(p, rinner, st::msgFileRadialLine, bg); - } - - style::sprite icon; - if (showPause) { - icon = outbg ? (selected ? st::msgFileOutPauseSelected : st::msgFileOutPause) : (selected ? st::msgFileInPauseSelected : st::msgFileInPause); - } else if (radial || _data->loading()) { - icon = outbg ? (selected ? st::msgFileOutCancelSelected : st::msgFileOutCancel) : (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } else if (loaded) { - if (_data->song() || _data->voice()) { - icon = outbg ? (selected ? st::msgFileOutPlaySelected : st::msgFileOutPlay) : (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); - } else if (_data->isImage()) { - icon = outbg ? (selected ? st::msgFileOutImageSelected : st::msgFileOutImage) : (selected ? st::msgFileInImageSelected : st::msgFileInImage); - } else { - icon = outbg ? (selected ? st::msgFileOutFileSelected : st::msgFileOutFile) : (selected ? st::msgFileInFileSelected : st::msgFileInFile); - } - } else { - icon = outbg ? (selected ? st::msgFileOutDownloadSelected : st::msgFileOutDownload) : (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - p.drawSpriteCenter(inner, icon); - } - int32 namewidth = _width - nameleft - nameright; - - if (auto voice = Get()) { - const VoiceWaveform *wf = 0; - uchar norm_value = 0; - if (_data->voice()) { - wf = &_data->voice()->waveform; - if (wf->isEmpty()) { - wf = 0; - if (loaded) { - Local::countVoiceWaveform(_data); - } - } else if (wf->at(0) < 0) { - wf = 0; - } else { - norm_value = _data->voice()->wavemax; - } - } - float64 prg = voice->_playback ? voice->_playback->a_progress.current() : 0; - - // rescale waveform by going in waveform.size * bar_count 1D grid - style::color active(outbg ? (selected ? st::msgWaveformOutActiveSelected : st::msgWaveformOutActive) : (selected ? st::msgWaveformInActiveSelected : st::msgWaveformInActive)); - style::color inactive(outbg ? (selected ? st::msgWaveformOutInactiveSelected : st::msgWaveformOutInactive) : (selected ? st::msgWaveformInInactiveSelected : st::msgWaveformInInactive)); - int32 wf_size = wf ? wf->size() : WaveformSamplesCount, availw = int32(namewidth + st::msgWaveformSkip), activew = qRound(availw * prg); - if (!outbg && !voice->_playback && _parent->isMediaUnread()) { - activew = availw; - } - int32 bar_count = qMin(availw / int32(st::msgWaveformBar + st::msgWaveformSkip), wf_size); - uchar max_value = 0; - int32 max_delta = st::msgWaveformMax - st::msgWaveformMin, bottom = st::msgFilePadding.top() + st::msgWaveformMax; - p.setPen(Qt::NoPen); - for (int32 i = 0, bar_x = 0, sum_i = 0; i < wf_size; ++i) { - uchar value = wf ? wf->at(i) : 0; - if (sum_i + bar_count >= wf_size) { // draw bar - sum_i = sum_i + bar_count - wf_size; - if (sum_i < (bar_count + 1) / 2) { - if (max_value < value) max_value = value; - } - int32 bar_value = ((max_value * max_delta) + ((norm_value + 1) / 2)) / (norm_value + 1); - - if (bar_x >= activew) { - p.fillRect(nameleft + bar_x, bottom - bar_value, st::msgWaveformBar, st::msgWaveformMin + bar_value, inactive); - } else if (bar_x + st::msgWaveformBar <= activew) { - p.fillRect(nameleft + bar_x, bottom - bar_value, st::msgWaveformBar, st::msgWaveformMin + bar_value, active); - } else { - p.fillRect(nameleft + bar_x, bottom - bar_value, activew - bar_x, st::msgWaveformMin + bar_value, active); - p.fillRect(nameleft + activew, bottom - bar_value, st::msgWaveformBar - (activew - bar_x), st::msgWaveformMin + bar_value, inactive); - } - bar_x += st::msgWaveformBar + st::msgWaveformSkip; - - if (sum_i < (bar_count + 1) / 2) { - max_value = 0; - } else { - max_value = value; - } - } else { - if (max_value < value) max_value = value; - - sum_i += bar_count; - } - } - } else if (auto named = Get()) { - p.setFont(st::semiboldFont); - p.setPen(st::black); - if (namewidth < named->_namew) { - p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(named->_name, namewidth)); - } else { - p.drawTextLeft(nameleft, nametop, _width, named->_name, named->_namew); - } - } - - style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); - p.setFont(st::normalFont); - p.setPen(status); - p.drawTextLeft(nameleft, statustop, _width, _statusText); - - if (_parent->isMediaUnread()) { - int32 w = st::normalFont->width(_statusText); - if (w + st::mediaUnreadSkip + st::mediaUnreadSize <= namewidth) { - p.setPen(Qt::NoPen); - p.setBrush(outbg ? (selected ? st::msgFileOutBgSelected : st::msgFileOutBg) : (selected ? st::msgFileInBgSelected : st::msgFileInBg)); - - p.setRenderHint(QPainter::HighQualityAntialiasing, true); - p.drawEllipse(rtlrect(nameleft + w + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width)); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - } - } - - if (auto captioned = Get()) { - p.setPen(st::black); - captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, selection); - } -} - -HistoryTextState HistoryDocument::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - bool loaded = _data->loaded(); - - bool showPause = updateStatusText(); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0; - if (auto thumbed = Get()) { - nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - linktop = st::msgFileThumbLinkTop; - bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - - QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); - - if ((_data->loading() || _data->uploading() || !loaded) && rthumb.contains(x, y)) { - result.link = (_data->loading() || _data->uploading()) ? _cancell : _savel; - return result; - } - - if (_data->status != FileUploadFailed) { - if (rtlrect(nameleft, linktop, thumbed->_linkw, st::semiboldFont->height, _width).contains(x, y)) { - result.link = (_data->loading() || _data->uploading()) ? thumbed->_linkcancell : thumbed->_linksavel; - return result; - } - } - } else { - bottom = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - if ((_data->loading() || _data->uploading() || !loaded) && inner.contains(x, y)) { - result.link = (_data->loading() || _data->uploading()) ? _cancell : _savel; - return result; - } - } - - int32 height = _height; - if (auto captioned = Get()) { - if (y >= bottom) { - result = captioned->_caption.getState(x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right(), request.forText()); - return result; - } - height -= captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } - if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->isValid()) { - result.link = _openl; - return result; - } - return result; -} - -QString HistoryDocument::notificationText() const { - QString result; - buildStringRepresentation([&result](const QString &type, const QString &fileName, const Text &caption) { - result = captionedNotificationText(fileName.isEmpty() ? type : fileName, caption); - }); - return result; -} - -QString HistoryDocument::inDialogsText() const { - QString result; - buildStringRepresentation([&result](const QString &type, const QString &fileName, const Text &caption) { - result = captionedInDialogsText(fileName.isEmpty() ? type : fileName, caption); - }); - return result; -} - -TextWithEntities HistoryDocument::selectedText(TextSelection selection) const { - TextWithEntities result; - buildStringRepresentation([&result, selection](const QString &type, const QString &fileName, const Text &caption) { - auto fullType = type; - if (!fileName.isEmpty()) { - fullType.append(qstr(" : ")).append(fileName); - } - result = captionedSelectedText(fullType, caption, selection); - }); - return result; -} - -template -void HistoryDocument::buildStringRepresentation(Callback callback) const { - const Text emptyCaption; - const Text *caption = &emptyCaption; - if (auto captioned = Get()) { - caption = &captioned->_caption; - } - QString attachType = lang(lng_in_dlg_file); - if (Has()) { - attachType = lang(lng_in_dlg_audio); - } else if (_data->song()) { - attachType = lang(lng_in_dlg_audio_file); - } - - QString attachFileName; - if (auto named = Get()) { - if (!named->_name.isEmpty()) { - attachFileName = named->_name; - } - } - return callback(attachType, attachFileName, *caption); -} - -void HistoryDocument::setStatusSize(int32 newSize, qint64 realDuration) const { - int32 duration = _data->song() ? _data->song()->duration : (_data->voice() ? _data->voice()->duration : -1); - HistoryFileMedia::setStatusSize(newSize, _data->size, duration, realDuration); - if (auto thumbed = Get()) { - if (_statusSize == FileStatusSizeReady) { - thumbed->_link = lang(lng_media_download).toUpper(); - } else if (_statusSize == FileStatusSizeLoaded) { - thumbed->_link = lang(lng_media_open_with).toUpper(); - } else if (_statusSize == FileStatusSizeFailed) { - thumbed->_link = lang(lng_media_download).toUpper(); - } else if (_statusSize >= 0) { - thumbed->_link = lang(lng_media_cancel).toUpper(); - } else { - thumbed->_link = lang(lng_media_open_with).toUpper(); - } - thumbed->_linkw = st::semiboldFont->width(thumbed->_link); - } -} - -bool HistoryDocument::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0, realDuration = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->status == FileUploading) { - statusSize = _data->uploadOffset; - } else if (_data->loading()) { - statusSize = _data->loadOffset(); - } else if (_data->loaded()) { - statusSize = FileStatusSizeLoaded; - if (audioPlayer()) { - if (_data->voice()) { - AudioMsgId playing; - auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice); - if (playing == AudioMsgId(_data, _parent->fullId()) && !(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) { - if (auto voice = Get()) { - bool was = voice->_playback; - voice->ensurePlayback(this); - if (!was || playbackState.position != voice->_playback->_position) { - float64 prg = playbackState.duration ? snap(float64(playbackState.position) / playbackState.duration, 0., 1.) : 0.; - if (voice->_playback->_position < playbackState.position) { - voice->_playback->a_progress.start(prg); - } else { - voice->_playback->a_progress = anim::fvalue(0., prg); - } - voice->_playback->_position = playbackState.position; - voice->_playback->_a_progress.start(); - } - } - - statusSize = -1 - (playbackState.position / (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency)); - realDuration = playbackState.duration / (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency); - showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting); - } else { - if (auto voice = Get()) { - voice->checkPlaybackFinished(); - } - } - } else if (_data->song()) { - AudioMsgId playing; - auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song); - if (playing == AudioMsgId(_data, _parent->fullId()) && !(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) { - statusSize = -1 - (playbackState.position / (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency)); - realDuration = playbackState.duration / (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency); - showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting); - } else { - } - if (!showPause && (playing == AudioMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) { - showPause = true; - } - } - } - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - setStatusSize(statusSize, realDuration); - } - return showPause; -} - -void HistoryDocument::step_voiceProgress(float64 ms, bool timer) { - if (auto voice = Get()) { - if (voice->_playback) { - float64 dt = ms / (2 * AudioVoiceMsgUpdateView); - if (dt >= 1) { - voice->_playback->_a_progress.stop(); - voice->_playback->a_progress.finish(); - } else { - voice->_playback->a_progress.update(qMin(dt, 1.), anim::linear); - } - if (timer) Ui::repaintHistoryItem(_parent); - } - } -} - -void HistoryDocument::attachToParent() { - App::regDocumentItem(_data, _parent); -} - -void HistoryDocument::detachFromParent() { - App::unregDocumentItem(_data, _parent); -} - -void HistoryDocument::updateSentMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaDocument) { - App::feedDocument(media.c_messageMediaDocument().vdocument, _data); - if (!_data->data().isEmpty()) { - if (_data->voice()) { - Local::writeAudio(_data->mediaKey(), _data->data()); - } else { - Local::writeStickerImage(_data->mediaKey(), _data->data()); - } - } - } -} - -bool HistoryDocument::needReSetInlineResultMedia(const MTPMessageMedia &media) { - return needReSetInlineResultDocument(media, _data); -} - -ImagePtr HistoryDocument::replyPreview() { - return _data->makeReplyPreview(); -} - -HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent) -, _data(document) -, _thumbw(1) -, _thumbh(1) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) -, _gif(nullptr) { - setDocumentLinks(_data, true); - - setStatusSize(FileStatusSizeReady); - - if (!caption.isEmpty()) { - _caption.setText(st::msgFont, caption + _parent->skipBlock(), itemTextNoMonoOptions(_parent)); - } - - _data->thumb->load(); -} - -HistoryGif::HistoryGif(HistoryItem *parent, const HistoryGif &other) : HistoryFileMedia(parent) -, _data(other._data) -, _thumbw(other._thumbw) -, _thumbh(other._thumbh) -, _caption(other._caption) -, _gif(nullptr) { - setDocumentLinks(_data, true); - - setStatusSize(other._statusSize); -} - -void HistoryGif::initDimensions() { - if (_caption.hasSkipBlock()) { - _caption.setSkipBlock(_parent->skipBlockWidth(), _parent->skipBlockHeight()); - } - - bool bubble = _parent->hasBubble(); - int32 tw = 0, th = 0; - if (gif() && _gif->state() == Media::Clip::State::Error) { - if (!_gif->autoplay()) { - Ui::showLayer(new InformBox(lang(lng_gif_error))); - } - App::unregGifItem(_gif); - delete _gif; - _gif = Media::Clip::BadReader; - } - - if (gif() && _gif->ready()) { - tw = convertScale(_gif->width()); - th = convertScale(_gif->height()); - } else { - tw = convertScale(_data->dimensions.width()), th = convertScale(_data->dimensions.height()); - if (!tw || !th) { - tw = convertScale(_data->thumb->width()); - th = convertScale(_data->thumb->height()); - } - } - if (tw > st::maxGifSize) { - th = (st::maxGifSize * th) / tw; - tw = st::maxGifSize; - } - if (th > st::maxGifSize) { - tw = (st::maxGifSize * tw) / th; - th = st::maxGifSize; - } - if (!tw || !th) { - tw = th = 1; - } - _thumbw = tw; - _thumbh = th; - _maxw = qMax(tw, int32(st::minPhotoSize)); - _minh = qMax(th, int32(st::minPhotoSize)); - _maxw = qMax(_maxw, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - if (!gif() || !_gif->ready()) { - _maxw = qMax(_maxw, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - } - if (bubble) { - _maxw += st::mediaPadding.left() + st::mediaPadding.right(); - _minh += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - _minh += st::mediaCaptionSkip + _caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } - } -} - -int HistoryGif::resizeGetHeight(int width) { - bool bubble = _parent->hasBubble(); - - int tw = 0, th = 0; - if (gif() && _gif->ready()) { - tw = convertScale(_gif->width()); - th = convertScale(_gif->height()); - } else { - tw = convertScale(_data->dimensions.width()), th = convertScale(_data->dimensions.height()); - if (!tw || !th) { - tw = convertScale(_data->thumb->width()); - th = convertScale(_data->thumb->height()); - } - } - if (tw > st::maxGifSize) { - th = (st::maxGifSize * th) / tw; - tw = st::maxGifSize; - } - if (th > st::maxGifSize) { - tw = (st::maxGifSize * tw) / th; - th = st::maxGifSize; - } - if (!tw || !th) { - tw = th = 1; - } - - if (bubble) { - width -= st::mediaPadding.left() + st::mediaPadding.right(); - } - if (width < tw) { - th = qRound((width / float64(tw)) * th); - tw = width; - } - _thumbw = tw; - _thumbh = th; - - _width = qMax(tw, int32(st::minPhotoSize)); - _height = qMax(th, int32(st::minPhotoSize)); - _width = qMax(_width, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - if (gif() && _gif->ready()) { - if (!_gif->started()) { - auto inWebPage = (_parent->getMedia() != this); - auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; - _gif->start(_thumbw, _thumbh, _width, _height, roundRadius); - } - } else { - _width = qMax(_width, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); - } - if (bubble) { - _width += st::mediaPadding.left() + st::mediaPadding.right(); - _height += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - _height += st::mediaCaptionSkip + _caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); - } - } - - return _height; -} - -void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - - _data->automaticLoad(_parent); - bool loaded = _data->loaded(), displayLoading = (_parent->id < 0) || _data->displayLoading(); - bool selected = (selection == FullSelection); - - if (loaded && !gif() && _gif != Media::Clip::BadReader && cAutoPlayGif()) { - Ui::autoplayMediaInlineAsync(_parent->fullId()); - } - - int32 skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - - int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); - - bool animating = (gif() && _gif->started()); - - if (!animating || _parent->id < 0) { - if (displayLoading) { - ensureAnimation(); - if (!_animation->radial.animating()) { - _animation->radial.start(dataProgress()); - } - } - updateStatusText(); - } - bool radial = isRadialAnimation(ms); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - if (!_caption.isEmpty()) { - height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); - } - } else { - App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); - } - - QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); - - if (animating) { - p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms)); - } else { - p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(ImageRoundRadius::Large, _thumbw, _thumbh, width, height)); - } - if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); - } - - if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == Media::Clip::BadReader)) { - float64 radialOpacity = (radial && loaded && _parent->id > 0) ? _animation->radial.opacity() : 1; - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgDateImgBgSelected); - } else if (isThumbAnimation(ms)) { - float64 over = _animation->a_thumbOver.current(); - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); - } - p.setOpacity(radialOpacity * p.opacity()); - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity(radialOpacity); - style::sprite icon; - if (_data->loaded() && !radial) { - icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); - } else if (radial || _data->loading()) { - if (_parent->id > 0 || _data->uploading()) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - if (!icon.isEmpty()) { - p.drawSpriteCenter(inner, icon); - } - if (radial) { - p.setOpacity(1); - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - - if (!animating || _parent->id < 0) { - int32 statusX = skipx + st::msgDateImgDelta + st::msgDateImgPadding.x(), statusY = skipy + st::msgDateImgDelta + st::msgDateImgPadding.y(); - int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); - int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); - App::roundRect(p, rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); - p.setFont(st::normalFont); - p.setPen(st::white); - p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x()); - } - } - - if (!_caption.isEmpty()) { - p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); - } else if (_parent->getMedia() == this && (_data->uploading() || App::hoveredItem() == _parent)) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); - } -} - -HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - if (!_caption.isEmpty()) { - int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); - height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); - if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); - return result; - } - height -= st::mediaCaptionSkip; - } - width -= st::mediaPadding.left() + st::mediaPadding.right(); - height -= skipy + st::mediaPadding.bottom(); - } - if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { - if (_data->uploading()) { - result.link = _cancell; - } else if (!gif() || !cAutoPlayGif()) { - result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); - } - if (_parent->getMedia() == this) { - int32 fullRight = skipx + width, fullBottom = skipy + height; - bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } - return result; - } - return result; -} - -QString HistoryGif::notificationText() const { - return captionedNotificationText(qsl("GIF"), _caption); -} - -QString HistoryGif::inDialogsText() const { - return captionedInDialogsText(qsl("GIF"), _caption); -} - -TextWithEntities HistoryGif::selectedText(TextSelection selection) const { - return captionedSelectedText(qsl("GIF"), _caption, selection); -} - -void HistoryGif::setStatusSize(int32 newSize) const { - HistoryFileMedia::setStatusSize(newSize, _data->size, -2, 0); -} - -void HistoryGif::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0, realDuration = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->status == FileUploading) { - statusSize = _data->uploadOffset; - } else if (_data->loading()) { - statusSize = _data->loadOffset(); - } else if (_data->loaded()) { - statusSize = FileStatusSizeLoaded; - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - setStatusSize(statusSize); - } -} - -void HistoryGif::attachToParent() { - App::regDocumentItem(_data, _parent); -} - -void HistoryGif::detachFromParent() { - App::unregDocumentItem(_data, _parent); -} - -void HistoryGif::updateSentMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaDocument) { - App::feedDocument(media.c_messageMediaDocument().vdocument, _data); - } -} - -bool HistoryGif::needReSetInlineResultMedia(const MTPMessageMedia &media) { - return needReSetInlineResultDocument(media, _data); -} - -ImagePtr HistoryGif::replyPreview() { - return _data->makeReplyPreview(); -} - -bool HistoryGif::playInline(bool autoplay) { - if (gif()) { - stopInline(); - } else if (_data->loaded(DocumentData::FilePathResolveChecked)) { - if (!cAutoPlayGif()) { - App::stopGifItems(); - } - _gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) { - _parent->clipCallback(notification); - }); - App::regGifItem(_gif, _parent); - if (gif()) _gif->setAutoplay(); - } - return true; -} - -void HistoryGif::stopInline() { - if (gif()) { - App::unregGifItem(_gif); - delete _gif; - _gif = 0; - } - - _parent->setPendingInitDimensions(); - Notify::historyItemLayoutChanged(_parent); -} - -HistoryGif::~HistoryGif() { - if (gif()) { - App::unregGifItem(_gif); - deleteAndMark(_gif); - } -} - -float64 HistoryGif::dataProgress() const { - return (_data->uploading() || !_parent || _parent->id > 0) ? _data->progress() : 0; -} - -bool HistoryGif::dataFinished() const { - return (!_parent || _parent->id > 0) ? (!_data->loading() && !_data->uploading()) : false; -} - -bool HistoryGif::dataLoaded() const { - return (!_parent || _parent->id > 0) ? _data->loaded() : false; -} - -namespace { - -class StickerClickHandler : public LeftButtonClickHandler { -public: - StickerClickHandler(const HistoryItem *item) : _item(item) { - } - -protected: - void onClickImpl() const override { - if (auto media = _item->getMedia()) { - if (auto document = media->getDocument()) { - if (auto sticker = document->sticker()) { - if (sticker->set.type() != mtpc_inputStickerSetEmpty && App::main()) { - App::main()->stickersBox(sticker->set); - } - } - } - } - } - -private: - const HistoryItem *_item; - -}; - -} // namespace - -HistorySticker::HistorySticker(HistoryItem *parent, DocumentData *document) : HistoryMedia(parent) -, _pixw(1) -, _pixh(1) -, _data(document) -, _emoji(_data->sticker()->alt) { - _data->thumb->load(); - if (auto e = emojiFromText(_emoji)) { - _emoji = emojiString(e); - } -} - -void HistorySticker::initDimensions() { - auto sticker = _data->sticker(); - - if (!_packLink && sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) { - _packLink = ClickHandlerPtr(new StickerClickHandler(_parent)); - } - _pixw = _data->dimensions.width(); - _pixh = _data->dimensions.height(); - if (_pixw > st::maxStickerSize) { - _pixh = (st::maxStickerSize * _pixh) / _pixw; - _pixw = st::maxStickerSize; - } - if (_pixh > st::maxStickerSize) { - _pixw = (st::maxStickerSize * _pixw) / _pixh; - _pixh = st::maxStickerSize; - } - if (_pixw < 1) _pixw = 1; - if (_pixh < 1) _pixh = 1; - _maxw = qMax(_pixw, int16(st::minPhotoSize)); - _minh = qMax(_pixh, int16(st::minPhotoSize)); - if (_parent->getMedia() == this) { - _maxw += additionalWidth(); - } - - _height = _minh; -} - -int HistorySticker::resizeGetHeight(int width) { // return new height - _width = qMin(width, _maxw); - if (_parent->getMedia() == this) { - auto via = _parent->Get(); - auto reply = _parent->Get(); - if (via || reply) { - int usew = _maxw - additionalWidth(via, reply); - int availw = _width - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.left(); - if (via) { - via->resize(availw); - } - if (reply) { - reply->resize(availw); - } - } - } - return _height; -} - -void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - auto sticker = _data->sticker(); - if (!sticker) return; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - - _data->checkSticker(); - bool loaded = _data->loaded(); - bool selected = (selection == FullSelection); - - bool out = _parent->out(), isPost = _parent->isPost(), childmedia = (_parent->getMedia() != this); - - int usew = _maxw, usex = 0; - auto via = childmedia ? nullptr : _parent->Get(); - auto reply = childmedia ? nullptr : _parent->Get(); - if (via || reply) { - usew -= additionalWidth(via, reply); - if (isPost) { - } else if (out) { - usex = _width - usew; - } - } - if (rtl()) usex = _width - usex - usew; - - if (selected) { - if (sticker->img->isNull()) { - p.drawPixmap(QPoint(usex + (usew - _pixw) / 2, (_minh - _pixh) / 2), _data->thumb->pixBlurredColored(st::msgStickerOverlay, _pixw, _pixh)); - } else { - p.drawPixmap(QPoint(usex + (usew - _pixw) / 2, (_minh - _pixh) / 2), sticker->img->pixColored(st::msgStickerOverlay, _pixw, _pixh)); - } - } else { - if (sticker->img->isNull()) { - p.drawPixmap(QPoint(usex + (usew - _pixw) / 2, (_minh - _pixh) / 2), _data->thumb->pixBlurred(_pixw, _pixh)); - } else { - p.drawPixmap(QPoint(usex + (usew - _pixw) / 2, (_minh - _pixh) / 2), sticker->img->pix(_pixw, _pixh)); - } - } - - if (!childmedia) { - _parent->drawInfo(p, usex + usew, _height, usex * 2 + usew, selected, InfoDisplayOverBackground); - - if (via || reply) { - int rectw = _width - usew - st::msgReplyPadding.left(); - int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); - if (via) { - recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); - } - if (reply) { - recth += st::msgReplyBarSize.height(); - } - int rectx = isPost ? (usew + st::msgReplyPadding.left()) : (out ? 0 : (usew + st::msgReplyPadding.left())); - int recty = _height - recth; - if (rtl()) rectx = _width - rectx - rectw; - - // Make the bottom of the rect at the same level as the bottom of the info rect. - recty -= st::msgDateImgDelta; - - App::roundRect(p, rectx, recty, rectw, recth, selected ? App::msgServiceSelectBg() : App::msgServiceBg(), selected ? StickerSelectedCorners : StickerCorners); - rectx += st::msgReplyPadding.left(); - rectw -= st::msgReplyPadding.left() + st::msgReplyPadding.right(); - if (via) { - p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * rectx + rectw, via->_text); - int skip = st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); - recty += skip; - } - if (reply) { - HistoryMessageReply::PaintFlags flags = 0; - if (selected) { - flags |= HistoryMessageReply::PaintSelected; - } - reply->paint(p, _parent, rectx, recty, rectw, flags); - } - } - } -} - -HistoryTextState HistorySticker::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - - bool out = _parent->out(), isPost = _parent->isPost(), childmedia = (_parent->getMedia() != this); - - int usew = _maxw, usex = 0; - auto via = childmedia ? nullptr : _parent->Get(); - auto reply = childmedia ? nullptr : _parent->Get(); - if (via || reply) { - usew -= additionalWidth(via, reply); - if (isPost) { - } else if (out) { - usex = _width - usew; - } - } - if (rtl()) usex = _width - usex - usew; - - if (via || reply) { - int rectw = _width - usew - st::msgReplyPadding.left(); - int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); - if (via) { - recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); - } - if (reply) { - recth += st::msgReplyBarSize.height(); - } - int rectx = isPost ? (usew + st::msgReplyPadding.left()) : (out ? 0 : (usew + st::msgReplyPadding.left())); - int recty = _height - recth; - if (rtl()) rectx = _width - rectx - rectw; - - // Make the bottom of the rect at the same level as the bottom of the info rect. - recty -= st::msgDateImgDelta; - - if (via) { - int viah = st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? 0 : st::msgReplyPadding.bottom()); - if (x >= rectx && y >= recty && x < rectx + rectw && y < recty + viah) { - result.link = via->_lnk; - return result; - } - int skip = st::msgServiceNameFont->height + (reply ? 2 * st::msgReplyPadding.top() : 0); - recty += skip; - recth -= skip; - } - if (reply) { - if (x >= rectx && y >= recty && x < rectx + rectw && y < recty + recth) { - result.link = reply->replyToLink(); - return result; - } - } - } - if (_parent->getMedia() == this) { - bool inDate = _parent->pointInTime(usex + usew, _height, x, y, InfoDisplayOverImage); - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } - - int pixLeft = usex + (usew - _pixw) / 2, pixTop = (_minh - _pixh) / 2; - if (x >= pixLeft && x < pixLeft + _pixw && y >= pixTop && y < pixTop + _pixh) { - result.link = _packLink; - return result; - } - return result; -} - -QString HistorySticker::toString() const { - return _emoji.isEmpty() ? lang(lng_in_dlg_sticker) : lng_in_dlg_sticker_emoji(lt_emoji, _emoji); -} - -QString HistorySticker::notificationText() const { - return toString(); -} - -TextWithEntities HistorySticker::selectedText(TextSelection selection) const { - if (selection != FullSelection) { - return TextWithEntities(); - } - return { qsl("[ ") + toString() + qsl(" ]"), EntitiesInText() }; -} - -void HistorySticker::attachToParent() { - App::regDocumentItem(_data, _parent); -} - -void HistorySticker::detachFromParent() { - App::unregDocumentItem(_data, _parent); -} - -void HistorySticker::updateSentMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaDocument) { - App::feedDocument(media.c_messageMediaDocument().vdocument, _data); - if (!_data->data().isEmpty()) { - Local::writeStickerImage(_data->mediaKey(), _data->data()); - } - } -} - -bool HistorySticker::needReSetInlineResultMedia(const MTPMessageMedia &media) { - return needReSetInlineResultDocument(media, _data); -} - -int HistorySticker::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const { - int result = 0; - if (via) { - accumulate_max(result, st::msgReplyPadding.left() + st::msgReplyPadding.left() + via->_maxWidth + st::msgReplyPadding.left()); - } - if (reply) { - accumulate_max(result, st::msgReplyPadding.left() + reply->replyToWidth()); - } - return result; -} - -void SendMessageClickHandler::onClickImpl() const { - Ui::showPeerHistory(peer()->id, ShowAtUnreadMsgId, Ui::ShowWay::Forward); -} - -void AddContactClickHandler::onClickImpl() const { - if (HistoryItem *item = App::histItemById(peerToChannel(peer()), msgid())) { - if (HistoryMedia *media = item->getMedia()) { - if (media->type() == MediaTypeContact) { - QString fname = static_cast(media)->fname(); - QString lname = static_cast(media)->lname(); - QString phone = static_cast(media)->phone(); - Ui::showLayer(new AddContactBox(fname, lname, phone)); - } - } - } -} - -HistoryContact::HistoryContact(HistoryItem *parent, int32 userId, const QString &first, const QString &last, const QString &phone) : HistoryMedia(parent) -, _userId(userId) -, _contact(0) -, _phonew(0) -, _fname(first) -, _lname(last) -, _phone(App::formatPhone(phone)) -, _linkw(0) { - _name.setText(st::semiboldFont, lng_full_name(lt_first_name, first, lt_last_name, last).trimmed(), _textNameOptions); - - _phonew = st::normalFont->width(_phone); -} - -void HistoryContact::initDimensions() { - _maxw = st::msgFileMinWidth; - - _contact = _userId ? App::userLoaded(_userId) : 0; - if (_contact) { - _contact->loadUserpic(); - } - if (_contact && _contact->contact > 0) { - _linkl.reset(new SendMessageClickHandler(_contact)); - _link = lang(lng_profile_send_message).toUpper(); - } else if (_userId) { - _linkl.reset(new AddContactClickHandler(_parent->history()->peer->id, _parent->id)); - _link = lang(lng_profile_add_contact).toUpper(); - } - _linkw = _link.isEmpty() ? 0 : st::semiboldFont->width(_link); - - int32 tleft = 0, tright = 0; - if (_userId) { - tleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - tright = st::msgFileThumbPadding.left(); - _maxw = qMax(_maxw, tleft + _phonew + tright); - } else { - tleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - tright = st::msgFileThumbPadding.left(); - _maxw = qMax(_maxw, tleft + _phonew + _parent->skipBlockWidth() + st::msgPadding.right()); - } - - _maxw = qMax(tleft + _name.maxWidth() + tright, _maxw); - _maxw = qMin(_maxw, int(st::msgMaxWidth)); - - if (_userId) { - _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - if (_parent->Has()) { - _minh += st::msgDateFont->height - st::msgDateDelta.y(); - } - } else { - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - } - _height = _minh; -} - -void HistoryContact::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - bool selected = (selection == FullSelection); - - if (width >= _maxw) { - width = _maxw; - } - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; - if (_userId) { - nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - nametop = st::msgFileThumbNameTop; - nameright = st::msgFileThumbPadding.left(); - statustop = st::msgFileThumbStatusTop; - linktop = st::msgFileThumbLinkTop; - - QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width)); - if (_contact) { - _contact->paintUserpic(p, st::msgFileThumbSize, rthumb.x(), rthumb.y()); - } else { - p.drawPixmap(rthumb.topLeft(), userDefPhoto(qAbs(_userId) % UserColorsCount)->pixCircled(st::msgFileThumbSize, st::msgFileThumbSize)); - } - if (selected) { - App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); - } - - bool over = ClickHandler::showAsActive(_linkl); - p.setFont(over ? st::semiboldFont->underline() : st::semiboldFont); - p.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg)); - p.drawTextLeft(nameleft, linktop, width, _link, _linkw); - } else { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nametop = st::msgFileNameTop; - nameright = st::msgFilePadding.left(); - statustop = st::msgFileStatusTop; - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width)); - p.drawPixmap(inner.topLeft(), userDefPhoto(qAbs(_parent->id) % UserColorsCount)->pixCircled(st::msgFileSize, st::msgFileSize)); - } - int32 namewidth = width - nameleft - nameright; - - p.setFont(st::semiboldFont); - p.setPen(st::black); - _name.drawLeftElided(p, nameleft, nametop, namewidth, width); - - style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); - p.setFont(st::normalFont); - p.setPen(status); - p.drawTextLeft(nameleft, statustop, width, _phone); -} - -HistoryTextState HistoryContact::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; - if (_userId) { - nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - linktop = st::msgFileThumbLinkTop; - if (rtlrect(nameleft, linktop, _linkw, st::semiboldFont->height, _width).contains(x, y)) { - result.link = _linkl; - return result; - } - } - if (x >= 0 && y >= 0 && x < _width && y < _height && _contact) { - result.link = _contact->openLink(); - return result; - } - return result; -} - -QString HistoryContact::notificationText() const { - return lang(lng_in_dlg_contact); -} - -TextWithEntities HistoryContact::selectedText(TextSelection selection) const { - if (selection != FullSelection) { - return TextWithEntities(); - } - return { qsl("[ ") + lang(lng_in_dlg_contact) + qsl(" ]\n") + _name.originalText() + '\n' + _phone, EntitiesInText() }; -} - -void HistoryContact::attachToParent() { - if (_userId) { - App::regSharedContactItem(_userId, _parent); - } -} - -void HistoryContact::detachFromParent() { - if (_userId) { - App::unregSharedContactItem(_userId, _parent); - } -} - -void HistoryContact::updateSentMedia(const MTPMessageMedia &media) { - if (media.type() == mtpc_messageMediaContact) { - if (_userId != media.c_messageMediaContact().vuser_id.v) { - detachFromParent(); - _userId = media.c_messageMediaContact().vuser_id.v; - attachToParent(); - } - } -} - -namespace { - QString siteNameFromUrl(const QString &url) { - QUrl u(url); - QString pretty = u.isValid() ? u.toDisplayString() : url; - QRegularExpressionMatch m = QRegularExpression(qsl("^[a-zA-Z0-9]+://")).match(pretty); - if (m.hasMatch()) pretty = pretty.mid(m.capturedLength()); - int32 slash = pretty.indexOf('/'); - if (slash > 0) pretty = pretty.mid(0, slash); - QStringList components = pretty.split('.', QString::SkipEmptyParts); - if (components.size() >= 2) { - components = components.mid(components.size() - 2); - return components.at(0).at(0).toUpper() + components.at(0).mid(1) + '.' + components.at(1); - } - return QString(); - } - - int32 articleThumbWidth(PhotoData *thumb, int32 height) { - int32 w = thumb->medium->width(), h = thumb->medium->height(); - return qMax(qMin(height * w / h, height), 1); - } - - int32 articleThumbHeight(PhotoData *thumb, int32 width) { - return qMax(thumb->medium->height() * width / thumb->medium->width(), 1); - } - - int32 _lineHeight = 0; -} // namespace - -HistoryWebPage::HistoryWebPage(HistoryItem *parent, WebPageData *data) : HistoryMedia(parent) -, _data(data) -, _title(st::msgMinWidth - st::webPageLeft) -, _description(st::msgMinWidth - st::webPageLeft) { -} - -HistoryWebPage::HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other) : HistoryMedia(parent) -, _data(other._data) -, _attach(other._attach ? other._attach->clone(parent) : nullptr) -, _asArticle(other._asArticle) -, _title(other._title) -, _description(other._description) -, _siteNameWidth(other._siteNameWidth) -, _durationWidth(other._durationWidth) -, _pixw(other._pixw) -, _pixh(other._pixh) { -} - -void HistoryWebPage::initDimensions() { - if (_data->pendingTill) { - _maxw = _minh = _height = 0; - return; - } - if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height); - - if (!_openl && !_data->url.isEmpty()) _openl.reset(new UrlClickHandler(_data->url, true)); - - // init layout - QString title(_data->title.isEmpty() ? _data->author : _data->title); - if (!_data->description.isEmpty() && title.isEmpty() && _data->siteName.isEmpty() && !_data->url.isEmpty()) { - _data->siteName = siteNameFromUrl(_data->url); - } - if (!_data->document && _data->photo && _data->type != WebPagePhoto && _data->type != WebPageVideo) { - if (_data->type == WebPageProfile) { - _asArticle = true; - } else if (_data->siteName == qstr("Twitter") || _data->siteName == qstr("Facebook")) { - _asArticle = false; - } else { - _asArticle = true; - } - if (_asArticle && _data->description.isEmpty() && title.isEmpty() && _data->siteName.isEmpty()) { - _asArticle = false; - } - } else { - _asArticle = false; - } - - // init attach - if (!_asArticle && !_attach) { - if (_data->document) { - if (_data->document->sticker()) { - _attach = std_::make_unique(_parent, _data->document); - } else if (_data->document->isAnimation()) { - _attach = std_::make_unique(_parent, _data->document, QString()); - } else if (_data->document->isVideo()) { - _attach = std_::make_unique(_parent, _data->document, QString()); - } else { - _attach = std_::make_unique(_parent, _data->document, QString()); - } - } else if (_data->photo) { - _attach = std_::make_unique(_parent, _data->photo, QString()); - } - } - - // init strings - if (_description.isEmpty() && !_data->description.isEmpty()) { - QString text = textClean(_data->description); - if (text.isEmpty()) { - _data->description = QString(); - } else { - if (!_asArticle && !_attach) { - text += _parent->skipBlock(); - } - const TextParseOptions *opts = &_webpageDescriptionOptions; - if (_data->siteName == qstr("Twitter")) { - opts = &_twitterDescriptionOptions; - } else if (_data->siteName == qstr("Instagram")) { - opts = &_instagramDescriptionOptions; - } - _description.setText(st::webPageDescriptionFont, text, *opts); - } - } - if (_title.isEmpty() && !title.isEmpty()) { - title = textOneLine(textClean(title)); - if (title.isEmpty()) { - if (_data->title.isEmpty()) { - _data->author = QString(); - } else { - _data->title = QString(); - } - } else { - if (!_asArticle && !_attach && _description.isEmpty()) { - title += _parent->skipBlock(); - } - _title.setText(st::webPageTitleFont, title, _webpageTitleOptions); - } - } - if (!_siteNameWidth && !_data->siteName.isEmpty()) { - _siteNameWidth = st::webPageTitleFont->width(_data->siteName); - } - - // init dimensions - int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right(); - int32 skipBlockWidth = _parent->skipBlockWidth(); - _maxw = skipBlockWidth; - _minh = 0; - - int32 siteNameHeight = _data->siteName.isEmpty() ? 0 : _lineHeight; - int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight; - int32 descMaxLines = (3 + (siteNameHeight ? 0 : 1) + (titleMinHeight ? 0 : 1)); - int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight); - int32 articleMinHeight = siteNameHeight + titleMinHeight + descriptionMinHeight; - int32 articlePhotoMaxWidth = 0; - if (_asArticle) { - articlePhotoMaxWidth = st::webPagePhotoDelta + qMax(articleThumbWidth(_data->photo, articleMinHeight), _lineHeight); - } - - if (_siteNameWidth) { - if (_title.isEmpty() && _description.isEmpty()) { - _maxw = qMax(_maxw, int32(_siteNameWidth + _parent->skipBlockWidth())); - } else { - _maxw = qMax(_maxw, int32(_siteNameWidth + articlePhotoMaxWidth)); - } - _minh += _lineHeight; - } - if (!_title.isEmpty()) { - _maxw = qMax(_maxw, int32(_title.maxWidth() + articlePhotoMaxWidth)); - _minh += titleMinHeight; - } - if (!_description.isEmpty()) { - _maxw = qMax(_maxw, int32(_description.maxWidth() + articlePhotoMaxWidth)); - _minh += descriptionMinHeight; - } - if (_attach) { - if (_minh) _minh += st::webPagePhotoSkip; - _attach->initDimensions(); - QMargins bubble(_attach->bubbleMargins()); - _maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top() + (_attach->customInfoLayout() ? skipBlockWidth : 0))); - _minh += _attach->minHeight() - bubble.top() - bubble.bottom(); - } - if (_data->type == WebPageVideo && _data->duration) { - _duration = formatDurationText(_data->duration); - _durationWidth = st::msgDateFont->width(_duration); - } - _maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); - _minh += st::msgPadding.bottom(); - if (_asArticle) { - _minh = resizeGetHeight(_maxw); // hack -// _minh += st::msgDateFont->height; - } -} - -int HistoryWebPage::resizeGetHeight(int width) { - if (_data->pendingTill) { - _width = width; - _height = _minh; - return _height; - } - - _width = qMin(width, _maxw); - width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); - - int32 linesMax = 5; - int32 siteNameLines = _siteNameWidth ? 1 : 0, siteNameHeight = _siteNameWidth ? _lineHeight : 0; - if (_asArticle) { - _pixh = linesMax * _lineHeight; - do { - _pixw = articleThumbWidth(_data->photo, _pixh); - int32 wleft = width - st::webPagePhotoDelta - qMax(_pixw, int16(_lineHeight)); - - _height = siteNameHeight; - - if (_title.isEmpty()) { - _titleLines = 0; - } else { - if (_title.countHeight(wleft) < 2 * st::webPageTitleFont->height) { - _titleLines = 1; - } else { - _titleLines = 2; - } - _height += _titleLines * _lineHeight; - } - - int32 descriptionHeight = _description.countHeight(wleft); - if (descriptionHeight < (linesMax - siteNameLines - _titleLines) * st::webPageDescriptionFont->height) { - _descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height); - } else { - _descriptionLines = (linesMax - siteNameLines - _titleLines); - } - _height += _descriptionLines * _lineHeight; - - if (_height >= _pixh) { - break; - } - - _pixh -= _lineHeight; - } while (_pixh > _lineHeight); - _height += st::msgDateFont->height; - } else { - _height = siteNameHeight; - - if (_title.isEmpty()) { - _titleLines = 0; - } else { - if (_title.countHeight(width) < 2 * st::webPageTitleFont->height) { - _titleLines = 1; - } else { - _titleLines = 2; - } - _height += _titleLines * _lineHeight; - } - - if (_description.isEmpty()) { - _descriptionLines = 0; - } else { - int32 descriptionHeight = _description.countHeight(width); - if (descriptionHeight < (linesMax - siteNameLines - _titleLines) * st::webPageDescriptionFont->height) { - _descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height); - } else { - _descriptionLines = (linesMax - siteNameLines - _titleLines); - } - _height += _descriptionLines * _lineHeight; - } - - if (_attach) { - if (_height) _height += st::webPagePhotoSkip; - - QMargins bubble(_attach->bubbleMargins()); - - _attach->resizeGetHeight(width + bubble.left() + bubble.right()); - _height += _attach->height() - bubble.top() - bubble.bottom(); - if (_attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) { - _height += st::msgDateFont->height; - } - } - } - _height += st::msgPadding.bottom(); - - return _height; -} - -void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - bool selected = (selection == FullSelection); - - style::color barfg = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); - style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); - - int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = st::msgPadding.bottom(); - width -= lshift + rshift; - QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); - if (_asArticle || (_attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) { - bshift += st::msgDateFont->height; - } - - QRect bar(rtlrect(st::msgPadding.left(), 0, st::webPageBar, _height - bshift, _width)); - p.fillRect(bar, barfg); - - if (_asArticle) { - _data->photo->medium->load(false, false); - bool full = _data->photo->medium->loaded(); - QPixmap pix; - int32 pw = qMax(_pixw, int16(_lineHeight)), ph = _pixh; - int32 pixw = _pixw, pixh = articleThumbHeight(_data->photo, _pixw); - int32 maxw = convertScale(_data->photo->medium->width()), maxh = convertScale(_data->photo->medium->height()); - if (pixw * ph != pixh * pw) { - float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw)); - pixh = qRound(pixh * coef); - pixw = qRound(pixw * coef); - } - if (full) { - pix = _data->photo->medium->pixSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph); - } else { - pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph); - } - p.drawPixmapLeft(lshift + width - pw, 0, _width, pix); - if (selected) { - App::roundRect(p, rtlrect(lshift + width - pw, 0, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); - } - width -= pw + st::webPagePhotoDelta; - } - int32 tshift = 0; - if (_siteNameWidth) { - p.setFont(st::webPageTitleFont); - p.setPen(semibold); - p.drawTextLeft(lshift, tshift, _width, (width >= _siteNameWidth) ? _data->siteName : st::webPageTitleFont->elided(_data->siteName, width)); - tshift += _lineHeight; - } - if (_titleLines) { - p.setPen(st::black); - int32 endskip = 0; - if (_title.hasSkipBlock()) { - endskip = _parent->skipBlockWidth(); - } - _title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection); - tshift += _titleLines * _lineHeight; - } - if (_descriptionLines) { - p.setPen(st::black); - int32 endskip = 0; - if (_description.hasSkipBlock()) { - endskip = _parent->skipBlockWidth(); - } - _description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection)); - tshift += _descriptionLines * _lineHeight; - } - if (_attach) { - if (tshift) tshift += st::webPagePhotoSkip; - - int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); - - p.save(); - p.translate(attachLeft, attachTop); - - auto attachSelection = selected ? FullSelection : TextSelection{ 0, 0 }; - _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); - int32 pixwidth = _attach->currentWidth(), pixheight = _attach->height(); - - if (_data->type == WebPageVideo && _attach->type() == MediaTypePhoto) { - if (_data->siteName == qstr("YouTube")) { - p.drawSprite(QPoint((pixwidth - st::youtubeIcon.pxWidth()) / 2, (pixheight - st::youtubeIcon.pxHeight()) / 2), st::youtubeIcon); - } else { - p.drawSprite(QPoint((pixwidth - st::videoIcon.pxWidth()) / 2, (pixheight - st::videoIcon.pxHeight()) / 2), st::videoIcon); - } - if (_durationWidth) { - int32 dateX = pixwidth - _durationWidth - st::msgDateImgDelta - 2 * st::msgDateImgPadding.x(); - int32 dateY = pixheight - st::msgDateFont->height - 2 * st::msgDateImgPadding.y() - st::msgDateImgDelta; - int32 dateW = pixwidth - dateX - st::msgDateImgDelta; - int32 dateH = pixheight - dateY - st::msgDateImgDelta; - - App::roundRect(p, dateX, dateY, dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); - - p.setFont(st::msgDateFont); - p.setPen(st::msgDateImgColor); - p.drawTextLeft(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y(), pixwidth, _duration); - } - } - - p.restore(); - } -} - -HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - - int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = st::msgPadding.bottom(); - width -= lshift + rshift; - QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); - if (_asArticle || (_attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) { - bshift += st::msgDateFont->height; - } - - bool inThumb = false; - if (_asArticle) { - int32 pw = qMax(_pixw, int16(_lineHeight)); - if (rtlrect(lshift + width - pw, 0, pw, _pixh, _width).contains(x, y)) { - inThumb = true; - } - width -= pw + st::webPagePhotoDelta; - } - int tshift = 0, symbolAdd = 0; - if (_siteNameWidth) { - tshift += _lineHeight; - } - if (_titleLines) { - if (y >= tshift && y < tshift + _titleLines * _lineHeight) { - Text::StateRequestElided titleRequest = request.forText(); - titleRequest.lines = _titleLines; - result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest); - } else if (y >= tshift + _titleLines * _lineHeight) { - symbolAdd += _title.length(); - } - tshift += _titleLines * _lineHeight; - } - if (_descriptionLines) { - if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) { - Text::StateRequestElided descriptionRequest = request.forText(); - descriptionRequest.lines = _descriptionLines; - result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest); - } else if (y >= tshift + _descriptionLines * _lineHeight) { - symbolAdd += _description.length(); - } - tshift += _descriptionLines * _lineHeight; - } - if (inThumb) { - result.link = _openl; - } else if (_attach) { - if (tshift) tshift += st::webPagePhotoSkip; - - if (x >= lshift && x < lshift + width && y >= tshift && y < _height - st::msgPadding.bottom()) { - int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); - result = _attach->getState(x - attachLeft, y - attachTop, request); - - if (result.link && !_data->document && _data->photo) { - if (_data->type == WebPageProfile || _data->type == WebPageVideo) { - result.link = _openl; - } else if (_data->type == WebPagePhoto || _data->siteName == qstr("Twitter") || _data->siteName == qstr("Facebook")) { - // leave photo link - } else { - result.link = _openl; - } - } - } - } - - result.symbol += symbolAdd; - return result; -} - -TextSelection HistoryWebPage::adjustSelection(TextSelection selection, TextSelectType type) const { - if (!_descriptionLines || selection.to <= _title.length()) { - return _title.adjustSelection(selection, type); - } - auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); - if (selection.from >= _title.length()) { - return fromDescriptionSelection(descriptionSelection); - } - auto titleSelection = _title.adjustSelection(selection, type); - return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; -} - -void HistoryWebPage::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (_attach) { - _attach->clickHandlerActiveChanged(p, active); - } -} - -void HistoryWebPage::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - if (_attach) { - _attach->clickHandlerPressedChanged(p, pressed); - } -} - -void HistoryWebPage::attachToParent() { - App::regWebPageItem(_data, _parent); - if (_attach) _attach->attachToParent(); -} - -void HistoryWebPage::detachFromParent() { - App::unregWebPageItem(_data, _parent); - if (_attach) _attach->detachFromParent(); -} - -TextWithEntities HistoryWebPage::selectedText(TextSelection selection) const { - if (selection == FullSelection) { - return TextWithEntities(); - } - auto titleResult = _title.originalTextWithEntities(selection, ExpandLinksAll); - auto descriptionResult = _description.originalTextWithEntities(toDescriptionSelection(selection), ExpandLinksAll); - if (titleResult.text.isEmpty()) { - return descriptionResult; - } else if (descriptionResult.text.isEmpty()) { - return titleResult; - } - - titleResult.text += '\n'; - appendTextWithEntities(titleResult, std_::move(descriptionResult)); - return titleResult; -} - -ImagePtr HistoryWebPage::replyPreview() { - return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr()); -} - -HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent) -, _data(data) -, _title(st::msgMinWidth - st::webPageLeft) -, _description(st::msgMinWidth - st::webPageLeft) { -} - -HistoryGame::HistoryGame(HistoryItem *parent, const HistoryGame &other) : HistoryMedia(parent) -, _data(other._data) -, _attach(other._attach ? other._attach->clone(parent) : nullptr) -, _title(other._title) -, _description(other._description) { -} - -void HistoryGame::initDimensions() { - if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height); - - if (!_openl && !_data->url.isEmpty()) _openl.reset(new UrlClickHandler(_data->url, true)); - - auto title = _data->title; - - // init attach - if (!_attach) { - if (_data->document) { - if (_data->document->sticker()) { - _attach = std_::make_unique(_parent, _data->document); - } else if (_data->document->isAnimation()) { - _attach = std_::make_unique(_parent, _data->document, QString()); - } else if (_data->document->isVideo()) { - _attach = std_::make_unique(_parent, _data->document, QString()); - } else { - _attach = std_::make_unique(_parent, _data->document, QString()); - } - } else if (_data->photo) { - _attach = std_::make_unique(_parent, _data->photo, QString()); - } - } - - // init strings - if (_description.isEmpty() && !_data->description.isEmpty()) { - auto text = textClean(_data->description); - if (text.isEmpty()) { - _data->description = QString(); - } else { - _description.setText(st::webPageDescriptionFont, text, _webpageDescriptionOptions); - } - } - if (_title.isEmpty() && !title.isEmpty()) { - title = textOneLine(textClean(title)); - if (title.isEmpty()) { - _data->title = QString(); - } else { - _title.setText(st::webPageTitleFont, title, _webpageTitleOptions); - } - } - - // init dimensions - int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right(); - int32 skipBlockWidth = _parent->skipBlockWidth(); - _maxw = skipBlockWidth; - _minh = st::msgPadding.top(); - - int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight; - int32 descMaxLines = (4 + (titleMinHeight ? 0 : 1)); - int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight); - - if (!_title.isEmpty()) { - _maxw = qMax(_maxw, int32(_title.maxWidth())); - _minh += titleMinHeight; - } - if (!_description.isEmpty()) { - _maxw = qMax(_maxw, int32(_description.maxWidth())); - _minh += descriptionMinHeight; - } - if (_attach) { - if (_minh) _minh += st::webPagePhotoSkip; - _attach->initDimensions(); - QMargins bubble(_attach->bubbleMargins()); - _maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top())); - _minh += _attach->minHeight() - bubble.top() - bubble.bottom(); - } - _maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); -} - -int HistoryGame::resizeGetHeight(int width) { - _width = qMin(width, _maxw); - width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); - - int32 linesMax = 5; - _height = st::msgPadding.top(); - if (_title.isEmpty()) { - _titleLines = 0; - } else { - if (_title.countHeight(width) < 2 * st::webPageTitleFont->height) { - _titleLines = 1; - } else { - _titleLines = 2; - } - _height += _titleLines * _lineHeight; - } - - if (_description.isEmpty()) { - _descriptionLines = 0; - } else { - int32 descriptionHeight = _description.countHeight(width); - if (descriptionHeight < (linesMax - _titleLines) * st::webPageDescriptionFont->height) { - _descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height); - } else { - _descriptionLines = (linesMax - _titleLines); - } - _height += _descriptionLines * _lineHeight; - } - - if (_attach) { - if (_height) _height += st::webPagePhotoSkip; - - QMargins bubble(_attach->bubbleMargins()); - - _attach->resizeGetHeight(width + bubble.left() + bubble.right()); - _height += _attach->height() - bubble.top() - bubble.bottom(); - } - - return _height; -} - -void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - int32 width = _width, height = _height; - - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - bool selected = (selection == FullSelection); - - style::color barfg = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); - style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); - - int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0; - width -= lshift + rshift; - QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); - - QRect bar(rtlrect(st::msgPadding.left(), st::msgPadding.top(), st::webPageBar, _height - bshift, _width)); - p.fillRect(bar, barfg); - - int32 tshift = st::msgPadding.top(); - if (_titleLines) { - p.setPen(st::black); - int32 endskip = 0; - if (_title.hasSkipBlock()) { - endskip = _parent->skipBlockWidth(); - } - _title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection); - tshift += _titleLines * _lineHeight; - } - if (_descriptionLines) { - p.setPen(st::black); - int32 endskip = 0; - if (_description.hasSkipBlock()) { - endskip = _parent->skipBlockWidth(); - } - _description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection)); - tshift += _descriptionLines * _lineHeight; - } - if (_attach) { - if (tshift) tshift += st::webPagePhotoSkip; - - int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); - if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); - - auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 }; - - p.translate(attachLeft, attachTop); - _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); - p.translate(-attachLeft, -attachTop); - } -} - -HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - int32 width = _width, height = _height; - - int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0; - width -= lshift + rshift; - QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); - - bool inThumb = false; - int tshift = st::msgPadding.top(), symbolAdd = 0; - if (_titleLines) { - if (y >= tshift && y < tshift + _titleLines * _lineHeight) { - Text::StateRequestElided titleRequest = request.forText(); - titleRequest.lines = _titleLines; - result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest); - } else if (y >= tshift + _titleLines * _lineHeight) { - symbolAdd += _title.length(); - } - tshift += _titleLines * _lineHeight; - } - if (_descriptionLines) { - if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) { - Text::StateRequestElided descriptionRequest = request.forText(); - descriptionRequest.lines = _descriptionLines; - result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest); - } else if (y >= tshift + _descriptionLines * _lineHeight) { - symbolAdd += _description.length(); - } - tshift += _descriptionLines * _lineHeight; - } - if (inThumb) { - result.link = _openl; - } else if (_attach) { - if (tshift) tshift += st::webPagePhotoSkip; - - if (x >= lshift && x < lshift + width && y >= tshift && y < _height) { - result.link = _openl; - } - } - - result.symbol += symbolAdd; - return result; -} - -TextSelection HistoryGame::adjustSelection(TextSelection selection, TextSelectType type) const { - if (!_descriptionLines || selection.to <= _title.length()) { - return _title.adjustSelection(selection, type); - } - auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); - if (selection.from >= _title.length()) { - return fromDescriptionSelection(descriptionSelection); - } - auto titleSelection = _title.adjustSelection(selection, type); - return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; -} - -void HistoryGame::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (_attach) { - _attach->clickHandlerActiveChanged(p, active); - } -} - -void HistoryGame::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - if (_attach) { - _attach->clickHandlerPressedChanged(p, pressed); - } -} - -void HistoryGame::attachToParent() { - App::regGameItem(_data, _parent); - if (_attach) _attach->attachToParent(); -} - -void HistoryGame::detachFromParent() { - App::unregGameItem(_data, _parent); - if (_attach) _attach->detachFromParent(); -} - -TextWithEntities HistoryGame::selectedText(TextSelection selection) const { - if (selection == FullSelection) { - return TextWithEntities(); - } - auto titleResult = _title.originalTextWithEntities(selection, ExpandLinksAll); - auto descriptionResult = _description.originalTextWithEntities(toDescriptionSelection(selection), ExpandLinksAll); - if (titleResult.text.isEmpty()) { - return descriptionResult; - } else if (descriptionResult.text.isEmpty()) { - return titleResult; - } - - titleResult.text += '\n'; - appendTextWithEntities(titleResult, std_::move(descriptionResult)); - return titleResult; -} - -ImagePtr HistoryGame::replyPreview() { - return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr()); -} - -HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent) -, _data(App::location(coords)) -, _title(st::msgMinWidth) -, _description(st::msgMinWidth) -, _link(new LocationClickHandler(coords)) { - if (!title.isEmpty()) { - _title.setText(st::webPageTitleFont, textClean(title), _webpageTitleOptions); - } - if (!description.isEmpty()) { - _description.setText(st::webPageDescriptionFont, textClean(description), _webpageDescriptionOptions); - } -} - -HistoryLocation::HistoryLocation(HistoryItem *parent, const HistoryLocation &other) : HistoryMedia(parent) -, _data(other._data) -, _title(other._title) -, _description(other._description) -, _link(new LocationClickHandler(_data->coords)) { -} - -void HistoryLocation::initDimensions() { - bool bubble = _parent->hasBubble(); - - int32 tw = fullWidth(), th = fullHeight(); - if (tw > st::maxMediaSize) { - th = (st::maxMediaSize * th) / tw; - tw = st::maxMediaSize; - } - int32 minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - _maxw = qMax(tw, int32(minWidth)); - _minh = qMax(th, int32(st::minPhotoSize)); - - if (bubble) { - _maxw += st::mediaPadding.left() + st::mediaPadding.right(); - if (!_title.isEmpty()) { - _minh += qMin(_title.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()), 2 * st::webPageTitleFont->height); - } - if (!_description.isEmpty()) { - _maxw = qMax(_maxw, int32(st::msgPadding.left() + _description.maxWidth() + st::msgPadding.right())); - _minh += qMin(_description.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()), 3 * st::webPageDescriptionFont->height); - } - _minh += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_title.isEmpty() || !_description.isEmpty()) { - _minh += st::webPagePhotoSkip; - if (!_parent->Has() && !_parent->Has()) { - _minh += st::msgPadding.top(); - } - } - } -} - -int HistoryLocation::resizeGetHeight(int width) { - bool bubble = _parent->hasBubble(); - - _width = qMin(width, _maxw); - if (bubble) { - _width -= st::mediaPadding.left() + st::mediaPadding.right(); - } - - int32 tw = fullWidth(), th = fullHeight(); - if (tw > st::maxMediaSize) { - th = (st::maxMediaSize * th) / tw; - tw = st::maxMediaSize; - } - _height = th; - if (tw > _width) { - _height = (_width * _height / tw); - } else { - _width = tw; - } - int32 minWidth = qMax(st::minPhotoSize, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); - _width = qMax(_width, int32(minWidth)); - _height = qMax(_height, int32(st::minPhotoSize)); - if (bubble) { - _width += st::mediaPadding.left() + st::mediaPadding.right(); - _height += st::mediaPadding.top() + st::mediaPadding.bottom(); - if (!_title.isEmpty()) { - _height += qMin(_title.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()), st::webPageTitleFont->height * 2); - } - if (!_description.isEmpty()) { - _height += qMin(_description.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()), st::webPageDescriptionFont->height * 3); - } - if (!_title.isEmpty() || !_description.isEmpty()) { - _height += st::webPagePhotoSkip; - if (!_parent->Has() && !_parent->Has()) { - _height += st::msgPadding.top(); - } - } - } - return _height; -} - -void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; - bool selected = (selection == FullSelection); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - - if (!_title.isEmpty() || !_description.isEmpty()) { - if (!_parent->Has() && !_parent->Has()) { - skipy += st::msgPadding.top(); - } - } - - width -= st::mediaPadding.left() + st::mediaPadding.right(); - int32 textw = _width - st::msgPadding.left() - st::msgPadding.right(); - - p.setPen(st::black); - if (!_title.isEmpty()) { - _title.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 2, style::al_left, 0, -1, 0, false, selection); - skipy += qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); - } - if (!_description.isEmpty()) { - _description.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 3, style::al_left, 0, -1, 0, false, toDescriptionSelection(selection)); - skipy += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); - } - if (!_title.isEmpty() || !_description.isEmpty()) { - skipy += st::webPagePhotoSkip; - } - height -= skipy + st::mediaPadding.bottom(); - } else { - App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); - } - - _data->load(); - QPixmap toDraw; - if (_data && !_data->thumb->isNull()) { - int32 w = _data->thumb->width(), h = _data->thumb->height(); - QPixmap pix; - if (width * h == height * w || (w == fullWidth() && h == fullHeight())) { - pix = _data->thumb->pixSingle(ImageRoundRadius::Large, width, height, width, height); - } else if (width * h > height * w) { - int32 nw = height * w / h; - pix = _data->thumb->pixSingle(ImageRoundRadius::Large, nw, height, width, height); - } else { - int32 nh = width * h / w; - pix = _data->thumb->pixSingle(ImageRoundRadius::Large, width, nh, width, height); - } - p.drawPixmap(QPoint(skipx, skipy), pix); - } else { - App::roundRect(p, skipx, skipy, width, height, st::white, MessageInCorners); - } - if (selected) { - App::roundRect(p, skipx, skipy, width, height, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); - } - - if (_parent->getMedia() == this) { - int32 fullRight = skipx + width, fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0); - _parent->drawInfo(p, fullRight, fullBottom, skipx * 2 + width, selected, InfoDisplayOverImage); - } -} - -HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - auto symbolAdd = 0; - - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; - int32 skipx = 0, skipy = 0, width = _width, height = _height; - bool bubble = _parent->hasBubble(); - - if (bubble) { - skipx = st::mediaPadding.left(); - skipy = st::mediaPadding.top(); - - if (!_title.isEmpty() || !_description.isEmpty()) { - if (!_parent->Has() && !_parent->Has()) { - skipy += st::msgPadding.top(); - } - } - - width -= st::mediaPadding.left() + st::mediaPadding.right(); - int32 textw = _width - st::msgPadding.left() - st::msgPadding.right(); - - if (!_title.isEmpty()) { - auto titleh = qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); - if (y >= skipy && y < skipy + titleh) { - result = _title.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); - return result; - } else if (y >= skipy + titleh) { - symbolAdd += _title.length(); - } - skipy += titleh; - } - if (!_description.isEmpty()) { - auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); - if (y >= skipy && y < skipy + descriptionh) { - result = _description.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); - } else if (y >= skipy + descriptionh) { - symbolAdd += _description.length(); - } - skipy += descriptionh; - } - if (!_title.isEmpty() || !_description.isEmpty()) { - skipy += st::webPagePhotoSkip; - } - height -= skipy + st::mediaPadding.bottom(); - } - if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height && _data) { - result.link = _link; - - int32 fullRight = skipx + width, fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0); - bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } - result.symbol += symbolAdd; - return result; -} - -TextSelection HistoryLocation::adjustSelection(TextSelection selection, TextSelectType type) const { - if (_description.isEmpty() || selection.to <= _title.length()) { - return _title.adjustSelection(selection, type); - } - auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); - if (selection.from >= _title.length()) { - return fromDescriptionSelection(descriptionSelection); - } - auto titleSelection = _title.adjustSelection(selection, type); - return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; -} - -QString HistoryLocation::notificationText() const { - return captionedNotificationText(lang(lng_maps_point), _title); -} - -QString HistoryLocation::inDialogsText() const { - return captionedInDialogsText(lang(lng_maps_point), _title); -} - -TextWithEntities HistoryLocation::selectedText(TextSelection selection) const { - if (selection == FullSelection) { - TextWithEntities result = { qsl("[ ") + lang(lng_maps_point) + qsl(" ]\n"), EntitiesInText() }; - auto info = selectedText(AllTextSelection); - if (!info.text.isEmpty()) { - appendTextWithEntities(result, std_::move(info)); - result.text.append('\n'); - } - result.text += _link->dragText(); - return result; - } - - auto titleResult = _title.originalTextWithEntities(selection); - auto descriptionResult = _description.originalTextWithEntities(toDescriptionSelection(selection)); - if (titleResult.text.isEmpty()) { - return descriptionResult; - } else if (descriptionResult.text.isEmpty()) { - return titleResult; - } - titleResult.text += '\n'; - appendTextWithEntities(titleResult, std_::move(descriptionResult)); - return titleResult; -} - -int32 HistoryLocation::fullWidth() const { - return st::locationSize.width(); -} - -int32 HistoryLocation::fullHeight() const { - return st::locationSize.height(); -} - -void ViaInlineBotClickHandler::onClickImpl() const { - App::insertBotCommand('@' + _bot->username); -} - -void HistoryMessageVia::create(int32 userId) { - _bot = App::user(peerFromUser(userId)); - _maxWidth = st::msgServiceNameFont->width(lng_inline_bot_via(lt_inline_bot, '@' + _bot->username)); - _lnk.reset(new ViaInlineBotClickHandler(_bot)); -} - -void HistoryMessageVia::resize(int32 availw) const { - if (availw < 0) { - _text = QString(); - _width = 0; - } else { - _text = lng_inline_bot_via(lt_inline_bot, '@' + _bot->username); - if (availw < _maxWidth) { - _text = st::msgServiceNameFont->elided(_text, availw); - _width = st::msgServiceNameFont->width(_text); - } else if (_width < _maxWidth) { - _width = _maxWidth; - } - } -} - -void HistoryMessageSigned::create(UserData *from, const QDateTime &date) { - QString time = qsl(", ") + date.toString(cTimeFormat()), name = App::peerName(from); - int32 timew = st::msgDateFont->width(time), namew = st::msgDateFont->width(name); - if (timew + namew > st::maxSignatureSize) { - name = st::msgDateFont->elided(from->firstName, st::maxSignatureSize - timew); - } - _signature.setText(st::msgDateFont, name + time, _textNameOptions); -} - -int HistoryMessageSigned::maxWidth() const { - return _signature.maxWidth(); -} - -void HistoryMessageEdited::create(const QDateTime &editDate, const QDateTime &date) { - _editDate = editDate; - - QString time = date.toString(cTimeFormat()); - _edited.setText(st::msgDateFont, lang(lng_edited) + ' ' + time, _textNameOptions); -} - -int HistoryMessageEdited::maxWidth() const { - return _edited.maxWidth(); -} - -void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { - QString text; - if (_authorOriginal != _fromOriginal) { - text = lng_forwarded_signed(lt_channel, App::peerName(_authorOriginal), lt_user, App::peerName(_fromOriginal)); - } else { - text = App::peerName(_authorOriginal); - } - if (via) { - if (_authorOriginal->isChannel()) { - text = lng_forwarded_channel_via(lt_channel, textcmdLink(1, text), lt_inline_bot, textcmdLink(2, '@' + via->_bot->username)); - } else { - text = lng_forwarded_via(lt_user, textcmdLink(1, text), lt_inline_bot, textcmdLink(2, '@' + via->_bot->username)); - } - } else { - if (_authorOriginal->isChannel()) { - text = lng_forwarded_channel(lt_channel, textcmdLink(1, text)); - } else { - text = lng_forwarded(lt_user, textcmdLink(1, text)); - } - } - TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto }; - textstyleSet(&st::inFwdTextStyle); - _text.setText(st::msgServiceNameFont, text, opts); - textstyleRestore(); - _text.setLink(1, (_originalId && _authorOriginal->isChannel()) ? ClickHandlerPtr(new GoToMessageClickHandler(_authorOriginal->id, _originalId)) : _authorOriginal->openLink()); - if (via) { - _text.setLink(2, via->_lnk); - } -} - -bool HistoryMessageReply::updateData(HistoryMessage *holder, bool force) { - if (!force) { - if (replyToMsg || !replyToMsgId) { - return true; - } - } - if (!replyToMsg) { - replyToMsg = App::histItemById(holder->channelId(), replyToMsgId); - if (replyToMsg) { - App::historyRegDependency(holder, replyToMsg); - } - } - - if (replyToMsg) { - replyToText.setText(st::msgFont, textClean(replyToMsg->inReplyText()), _textDlgOptions); - - updateName(); - - replyToLnk.reset(new GoToMessageClickHandler(replyToMsg->history()->peer->id, replyToMsg->id)); - if (!replyToMsg->Has()) { - if (auto bot = replyToMsg->viaBot()) { - _replyToVia.reset(new HistoryMessageVia()); - _replyToVia->create(peerToUser(bot->id)); - } - } - } else if (force) { - replyToMsgId = 0; - } - if (force) { - holder->setPendingInitDimensions(); - } - return (replyToMsg || !replyToMsgId); -} - -void HistoryMessageReply::clearData(HistoryMessage *holder) { - _replyToVia = nullptr; - if (replyToMsg) { - App::historyUnregDependency(holder, replyToMsg); - replyToMsg = nullptr; - } - replyToMsgId = 0; -} - -bool HistoryMessageReply::isNameUpdated() const { - if (replyToMsg && replyToMsg->author()->nameVersion > replyToVersion) { - updateName(); - return true; - } - return false; -} - -void HistoryMessageReply::updateName() const { - if (replyToMsg) { - QString name = (_replyToVia && replyToMsg->author()->isUser()) ? replyToMsg->author()->asUser()->firstName : App::peerName(replyToMsg->author()); - replyToName.setText(st::msgServiceNameFont, name, _textNameOptions); - replyToVersion = replyToMsg->author()->nameVersion; - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - int32 w = replyToName.maxWidth(); - if (_replyToVia) { - w += st::msgServiceFont->spacew + _replyToVia->_maxWidth; - } - - _maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), int32(st::maxSignatureSize))); - } else { - _maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message)); - } - _maxReplyWidth = st::msgReplyPadding.left() + st::msgReplyBarSkip + _maxReplyWidth + st::msgReplyPadding.right(); -} - -void HistoryMessageReply::resize(int width) const { - if (_replyToVia) { - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - _replyToVia->resize(width - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew); - } -} - -void HistoryMessageReply::itemRemoved(HistoryMessage *holder, HistoryItem *removed) { - if (replyToMsg == removed) { - clearData(holder); - holder->setPendingInitDimensions(); - } -} - -void HistoryMessageReply::paint(Painter &p, const HistoryItem *holder, int x, int y, int w, PaintFlags flags) const { - bool selected = (flags & PaintSelected), outbg = holder->hasOutLayout(); - - style::color bar; - if (flags & PaintInBubble) { - bar = ((flags & PaintSelected) ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); - } else { - bar = st::white; - } - QRect rbar(rtlrect(x + st::msgReplyBarPos.x(), y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.width(), st::msgReplyBarSize.height(), w + 2 * x)); - p.fillRect(rbar, bar); - - if (w > st::msgReplyBarSkip) { - if (replyToMsg) { - bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; - int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - - if (hasPreview) { - ImagePtr replyPreview = replyToMsg->getMedia()->replyPreview(); - if (!replyPreview->isNull()) { - QRect to(rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x)); - p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(ImageRoundRadius::Small, replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); - if (selected) { - App::roundRect(p, to, textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); - } - } - } - if (w > st::msgReplyBarSkip + previewSkip) { - if (flags & PaintInBubble) { - p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - } else { - p.setPen(st::white); - } - replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x); - if (_replyToVia && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) { - p.setFont(st::msgServiceFont); - p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, _replyToVia->_text); - } - - HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage(); - if (!(flags & PaintInBubble)) { - } else if ((replyToAsMsg && replyToAsMsg->emptyText()) || replyToMsg->serviceMsg()) { - style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); - p.setPen(date); - } else { - p.setPen(st::msgColor); - } - replyToText.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top() + st::msgServiceNameFont->height, w - st::msgReplyBarSkip - previewSkip, w + 2 * x); - } - } else { - p.setFont(st::msgDateFont); - style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); - p.setPen((flags & PaintInBubble) ? date : st::white); - p.drawTextLeft(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2, w + 2 * x, st::msgDateFont->elided(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message), w - st::msgReplyBarSkip)); - } - } -} - -void HistoryMessage::KeyboardStyle::startPaint(Painter &p) const { - p.setPen(st::msgServiceColor); -} - -style::font HistoryMessage::KeyboardStyle::textFont() const { - return st::msgServiceFont; -} - -void HistoryMessage::KeyboardStyle::repaint(const HistoryItem *item) const { - Ui::repaintHistoryItem(item); -} - -void HistoryMessage::KeyboardStyle::paintButtonBg(Painter &p, const QRect &rect, bool down, float64 howMuchOver) const { - App::roundRect(p, rect, App::msgServiceBg(), StickerCorners); - if (down) { - howMuchOver = 1.; - } - if (howMuchOver > 0) { - float64 o = p.opacity(); - p.setOpacity(o * (howMuchOver * st::msgBotKbOverOpacity)); - App::roundRect(p, rect, st::white, WhiteCorners); - p.setOpacity(o); - } -} - -void HistoryMessage::KeyboardStyle::paintButtonIcon(Painter &p, const QRect &rect, HistoryMessageReplyMarkup::Button::Type type) const { - using Button = HistoryMessageReplyMarkup::Button; - style::sprite sprite; - switch (type) { - case Button::Type::Url: sprite = st::msgBotKbUrlIcon; break; -// case Button::Type::RequestPhone: sprite = st::msgBotKbRequestPhoneIcon; break; -// case Button::Type::RequestLocation: sprite = st::msgBotKbRequestLocationIcon; break; - case Button::Type::SwitchInlineSame: - case Button::Type::SwitchInline: sprite = st::msgBotKbSwitchPmIcon; break; - } - if (!sprite.isEmpty()) { - p.drawSprite(rect.x() + rect.width() - sprite.pxWidth() - st::msgBotKbIconPadding, rect.y() + st::msgBotKbIconPadding, sprite); - } -} - -void HistoryMessage::KeyboardStyle::paintButtonLoading(Painter &p, const QRect &rect) const { - style::sprite sprite = st::msgInvSendingImg; - p.drawSprite(rect.x() + rect.width() - sprite.pxWidth() - st::msgBotKbIconPadding, rect.y() + rect.height() - sprite.pxHeight() - st::msgBotKbIconPadding, sprite); -} - -int HistoryMessage::KeyboardStyle::minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const { - using Button = HistoryMessageReplyMarkup::Button; - int result = 2 * buttonPadding(), iconWidth = 0; - switch (type) { - case Button::Type::Url: iconWidth = st::msgBotKbUrlIcon.pxWidth(); break; - //case Button::Type::RequestPhone: iconWidth = st::msgBotKbRequestPhoneIcon.pxWidth(); break; - //case Button::Type::RequestLocation: iconWidth = st::msgBotKbRequestLocationIcon.pxWidth(); break; - case Button::Type::SwitchInlineSame: - case Button::Type::SwitchInline: iconWidth = st::msgBotKbSwitchPmIcon.pxWidth(); break; - case Button::Type::Callback: - case Button::Type::Game: iconWidth = st::msgInvSendingImg.pxWidth(); break; - } - if (iconWidth > 0) { - result = std::max(result, 2 * iconWidth + 4 * int(st::msgBotKbIconPadding)); - } - return result; -} - -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) { - CreateConfig config; - - if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { - const auto &f(msg.vfwd_from.c_messageFwdHeader()); - if (f.has_from_id() || f.has_channel_id()) { - 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; - } - } - 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; - if (msg.has_edit_date()) config.editDate = ::date(msg.vedit_date); - - createComponents(config); - - QString text(textClean(qs(msg.vmessage))); - initMedia(msg.has_media() ? (&msg.vmedia) : nullptr, text); - - TextWithEntities textWithEntities = { text, EntitiesInText() }; - if (msg.has_entities()) { - textWithEntities.entities = entitiesFromMTP(msg.ventities.c_vector().v); - } - setText(textWithEntities); -} - -namespace { - -MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMessage *fwd) { - MTPDmessage::Flags result = newMessageFlags(p) | MTPDmessage::Flag::f_fwd_from; - if (from) { - result |= MTPDmessage::Flag::f_from_id; - } - if (fwd->Has()) { - result |= MTPDmessage::Flag::f_via_bot_id; - } - if (!p->isChannel()) { - if (HistoryMedia *media = fwd->getMedia()) { - if (media->type() == MediaTypeVoiceFile) { - result |= MTPDmessage::Flag::f_media_unread; -// } else if (media->type() == MediaTypeVideo) { -// result |= MTPDmessage::flag_media_unread; - } - } - } - if (fwd->hasViews()) { - result |= MTPDmessage::Flag::f_views; - } - return result; -} - -} // namespace - -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; - - config.authorIdOriginal = fwd->authorOriginal()->id; - config.fromIdOriginal = fwd->fromOriginal()->id; - if (fwd->authorOriginal()->isChannel()) { - config.originalId = fwd->id; - } - auto fwdViaBot = fwd->viaBot(); - 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.reset(mediaOriginal->clone(this)); - } - setText(fwd->originalText()); -} - -HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities) -: HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createComponentsHelper(flags, replyTo, viaBotId, MTPnullMarkup); - - setText(textWithEntities); -} - -HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup) -: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createComponentsHelper(flags, replyTo, viaBotId, markup); - - initMediaFromDocument(doc, caption); - setText(TextWithEntities()); -} - -HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup) -: HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createComponentsHelper(flags, replyTo, viaBotId, markup); - - _media.reset(new HistoryPhoto(this, photo, caption)); - setText(TextWithEntities()); -} - -void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, const MTPReplyMarkup &markup) { - 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 (flags & MTPDmessage::Flag::f_reply_markup) config.markup = &markup; - if (isPost()) config.viewsCount = 1; - - createComponents(config); -} - -bool HistoryMessage::displayEditedBadge(bool hasViaBot) const { - if (!(_flags & MTPDmessage::Flag::f_edit_date)) { - return false; - } - if (auto fromUser = from()->asUser()) { - if (fromUser->botInfo) { - return false; - } - } - if (hasViaBot) { - return false; - } - return true; -} - - -void HistoryMessage::createComponents(const CreateConfig &config) { - uint64 mask = 0; - if (config.replyTo) { - mask |= HistoryMessageReply::Bit(); - } - if (config.viaBotId) { - mask |= HistoryMessageVia::Bit(); - } - if (config.viewsCount >= 0) { - mask |= HistoryMessageViews::Bit(); - } - if (isPost() && _from->isUser()) { - mask |= HistoryMessageSigned::Bit(); - } - if (displayEditedBadge(config.viaBotId != 0)) { - mask |= HistoryMessageEdited::Bit(); - } - 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 = config.replyTo; - if (!reply->updateData(this) && App::api()) { - App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId())); - } - } - if (auto via = Get()) { - via->create(config.viaBotId); - } - if (auto views = Get()) { - views->_views = config.viewsCount; - } - if (auto msgsigned = Get()) { - msgsigned->create(_from->asUser(), date); - } - if (auto edited = Get()) { - edited->create(config.editDate, date); - } - if (auto fwd = Get()) { - fwd->_authorOriginal = App::peer(config.authorIdOriginal); - fwd->_fromOriginal = App::peer(config.fromIdOriginal); - fwd->_originalId = config.originalId; - } - if (auto markup = Get()) { - markup->create(*config.markup); - if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) { - _flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button; - } - } - initTime(); -} - -QString formatViewsCount(int32 views) { - if (views > 999999) { - views /= 100000; - if (views % 10) { - return QString::number(views / 10) + '.' + QString::number(views % 10) + 'M'; - } - return QString::number(views / 10) + 'M'; - } else if (views > 9999) { - views /= 100; - if (views % 10) { - return QString::number(views / 10) + '.' + QString::number(views % 10) + 'K'; - } - return QString::number(views / 10) + 'K'; - } else if (views > 0) { - return QString::number(views); - } - return qsl("1"); -} - -void HistoryMessage::initTime() { - if (auto msgsigned = Get()) { - _timeWidth = msgsigned->maxWidth(); - } else if (auto edited = Get()) { - _timeWidth = edited->maxWidth(); - } else { - _timeText = date.toString(cTimeFormat()); - _timeWidth = st::msgDateFont->width(_timeText); - } - if (auto views = Get()) { - views->_viewsText = (views->_views >= 0) ? formatViewsCount(views->_views) : QString(); - views->_viewsWidth = views->_viewsText.isEmpty() ? 0 : st::msgDateFont->width(views->_viewsText); - } -} - -void HistoryMessage::initMedia(const MTPMessageMedia *media, QString ¤tText) { - switch (media ? media->type() : mtpc_messageMediaEmpty) { - case mtpc_messageMediaContact: { - auto &d = media->c_messageMediaContact(); - _media.reset(new HistoryContact(this, d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number))); - } break; - case mtpc_messageMediaGeo: { - auto &point = media->c_messageMediaGeo().vgeo; - if (point.type() == mtpc_geoPoint) { - _media.reset(new HistoryLocation(this, LocationCoords(point.c_geoPoint()))); - } - } break; - case mtpc_messageMediaVenue: { - auto &d = media->c_messageMediaVenue(); - if (d.vgeo.type() == mtpc_geoPoint) { - _media.reset(new HistoryLocation(this, LocationCoords(d.vgeo.c_geoPoint()), qs(d.vtitle), qs(d.vaddress))); - } - } break; - case mtpc_messageMediaPhoto: { - auto &photo = media->c_messageMediaPhoto(); - if (photo.vphoto.type() == mtpc_photo) { - _media.reset(new HistoryPhoto(this, App::feedPhoto(photo.vphoto.c_photo()), qs(photo.vcaption))); - } - } break; - case mtpc_messageMediaDocument: { - auto &document = media->c_messageMediaDocument().vdocument; - if (document.type() == mtpc_document) { - return initMediaFromDocument(App::feedDocument(document), qs(media->c_messageMediaDocument().vcaption)); - } - } break; - case mtpc_messageMediaWebPage: { - auto &d = media->c_messageMediaWebPage().vwebpage; - switch (d.type()) { - case mtpc_webPageEmpty: break; - case mtpc_webPagePending: { - _media.reset(new HistoryWebPage(this, App::feedWebPage(d.c_webPagePending()))); - } break; - case mtpc_webPage: { - _media.reset(new HistoryWebPage(this, App::feedWebPage(d.c_webPage()))); - } break; - } - } break; - case mtpc_messageMediaGame: { - auto &d = media->c_messageMediaGame().vgame; - if (d.type() == mtpc_game) { - _media.reset(new HistoryGame(this, App::feedGame(d.c_game()))); - } - } break; - }; -} - -void HistoryMessage::initMediaFromDocument(DocumentData *doc, const QString &caption) { - if (doc->sticker()) { - _media.reset(new HistorySticker(this, doc)); - } else if (doc->isAnimation()) { - _media.reset(new HistoryGif(this, doc, caption)); - } else if (doc->isVideo()) { - _media.reset(new HistoryVideo(this, doc, caption)); - } else { - _media.reset(new HistoryDocument(this, doc, caption)); - } -} - -int32 HistoryMessage::plainMaxWidth() const { - return st::msgPadding.left() + _text.maxWidth() + st::msgPadding.right(); -} - -void HistoryMessage::initDimensions() { - auto reply = Get(); - if (reply) { - reply->updateName(); - } - if (drawBubble()) { - auto fwd = Get(); - auto via = Get(); - if (fwd) { - fwd->create(via); - } - - if (_media) { - _media->initDimensions(); - if (_media->isDisplayed() && !_media->isAboveMessage()) { - if (_text.hasSkipBlock()) { - _text.removeSkipBlock(); - _textWidth = -1; - _textHeight = 0; - } - } else if (!_text.hasSkipBlock()) { - _text.setSkipBlock(skipBlockWidth(), skipBlockHeight()); - _textWidth = -1; - _textHeight = 0; - } - } - - _maxw = plainMaxWidth(); - if (emptyText()) { - _minh = 0; - } else { - _minh = st::msgPadding.top() + _text.minHeight() + st::msgPadding.bottom(); - } - if (_media && _media->isDisplayed()) { - int32 maxw = _media->maxWidth(); - if (maxw > _maxw) _maxw = maxw; - _minh += _media->minHeight(); - } - if (!_media) { - if (displayFromName()) { - int32 namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right(); - if (via && !fwd) { - namew += st::msgServiceFont->spacew + via->_maxWidth; - } - if (namew > _maxw) _maxw = namew; - } else if (via && !fwd) { - if (st::msgPadding.left() + via->_maxWidth + st::msgPadding.right() > _maxw) { - _maxw = st::msgPadding.left() + via->_maxWidth + st::msgPadding.right(); - } - } - if (fwd) { - int32 _namew = st::msgPadding.left() + fwd->_text.maxWidth() + st::msgPadding.right(); - if (via) { - _namew += st::msgServiceFont->spacew + via->_maxWidth; - } - if (_namew > _maxw) _maxw = _namew; - } - } - } else if (_media) { - _media->initDimensions(); - _maxw = _media->maxWidth(); - _minh = _media->minHeight(); - } else { - _maxw = st::msgMinWidth; - _minh = 0; - } - if (reply && !emptyText()) { - int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); - if (reply->_replyToVia) { - replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth; - } - if (replyw > _maxw) _maxw = replyw; - } - if (auto markup = inlineReplyMarkup()) { - if (!markup->inlineKeyboard) { - markup->inlineKeyboard.reset(new ReplyKeyboard(this, std_::make_unique(st::msgBotKbButton))); - } - - // if we have a text bubble we can resize it to fit the keyboard - // but if we have only media we don't do that - if (!emptyText()) { - _maxw = qMax(_maxw, markup->inlineKeyboard->naturalWidth()); - } - } -} - -void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const { - int32 maxwidth = qMin(int(st::msgMaxWidth), _maxw), hwidth = _history->width; - if (_media && _media->currentWidth() < maxwidth) { - maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth())); - } - - left = (!isPost() && out() && !Adaptive::Wide()) ? st::msgMargin.right() : st::msgMargin.left(); - if (hasFromPhoto()) { - left += st::msgPhotoSkip; -// } else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) { -// left += st::msgPhotoSkip - (hmaxwidth - hwidth); - } - - width = hwidth - st::msgMargin.left() - st::msgMargin.right(); - if (width > maxwidth) { - if (!isPost() && out() && !Adaptive::Wide()) { - left += width - maxwidth; - } - width = maxwidth; - } -} - -void HistoryMessage::fromNameUpdated(int32 width) const { - _authorNameVersion = author()->nameVersion; - if (!Has()) { - if (auto via = Get()) { - via->resize(width - st::msgPadding.left() - st::msgPadding.right() - author()->nameText.maxWidth() - st::msgServiceFont->spacew); - } - } -} - -void HistoryMessage::applyEdition(const MTPDmessage &message) { - int keyboardTop = -1; - if (!pendingResize()) { - if (auto keyboard = inlineReplyKeyboard()) { - int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); - keyboardTop = _height - h + st::msgBotKbButton.margin - marginBottom(); - } - } - - if (message.has_edit_date()) { - _flags |= MTPDmessage::Flag::f_edit_date; - if (displayEditedBadge(Has())) { - if (!Has()) { - AddComponents(HistoryMessageEdited::Bit()); - } - Get()->create(::date(message.vedit_date), date); - } else if (Has()) { - RemoveComponents(HistoryMessageEdited::Bit()); - } - initTime(); - } - - TextWithEntities textWithEntities = { qs(message.vmessage), EntitiesInText() }; - if (message.has_entities()) { - textWithEntities.entities = entitiesFromMTP(message.ventities.c_vector().v); - } - setText(textWithEntities); - setMedia(message.has_media() ? (&message.vmedia) : nullptr); - setReplyMarkup(message.has_reply_markup() ? (&message.vreply_markup) : nullptr); - setViewsCount(message.has_views() ? message.vviews.v : -1); - - finishEdition(keyboardTop); -} - -void HistoryMessage::applyEdition(const MTPDmessageService &message) { - if (message.vaction.type() == mtpc_messageActionHistoryClear) { - applyEditionToEmpty(); - } -} - -void HistoryMessage::applyEditionToEmpty() { - setEmptyText(); - setMedia(nullptr); - setReplyMarkup(nullptr); - setViewsCount(-1); - - finishEditionToEmpty(); -} - -void HistoryMessage::updateMedia(const MTPMessageMedia *media) { - auto setMediaAllowed = [](HistoryMediaType type) { - return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation); - }; - if (_flags & MTPDmessage_ClientFlag::f_from_inline_bot) { - bool needReSet = true; - if (media && _media) { - needReSet = _media->needReSetInlineResultMedia(*media); - } - if (needReSet) { - setMedia(media); - } - _flags &= ~MTPDmessage_ClientFlag::f_from_inline_bot; - } else if (media && _media && !setMediaAllowed(_media->type())) { - _media->updateSentMedia(*media); - } else { - setMedia(media); - } - setPendingInitDimensions(); -} - -int32 HistoryMessage::addToOverview(AddToOverviewMethod method) { - if (!indexInOverview()) return 0; - - int32 result = 0; - if (HistoryMedia *media = getMedia()) { - MediaOverviewType type = messageMediaToOverviewType(media); - if (type != OverviewCount) { - if (history()->addToOverview(type, id, method)) { - result |= (1 << type); - } - } - } - if (hasTextLinks()) { - if (history()->addToOverview(OverviewLinks, id, method)) { - result |= (1 << OverviewLinks); - } - } - return result; -} - -void HistoryMessage::eraseFromOverview() { - if (HistoryMedia *media = getMedia()) { - MediaOverviewType type = messageMediaToOverviewType(media); - if (type != OverviewCount) { - history()->eraseFromOverview(type, id); - } - } - if (hasTextLinks()) { - history()->eraseFromOverview(OverviewLinks, id); - } -} - -TextWithEntities HistoryMessage::selectedText(TextSelection selection) const { - TextWithEntities result, textResult, mediaResult; - if (selection == FullSelection) { - textResult = _text.originalTextWithEntities(AllTextSelection, ExpandLinksAll); - } else { - textResult = _text.originalTextWithEntities(selection, ExpandLinksAll); - } - if (_media) { - mediaResult = _media->selectedText(toMediaSelection(selection)); - } - if (textResult.text.isEmpty()) { - result = mediaResult; - } else if (mediaResult.text.isEmpty()) { - result = textResult; - } else { - result.text = textResult.text + qstr("\n\n"); - result.entities = textResult.entities; - appendTextWithEntities(result, std_::move(mediaResult)); - } - if (auto fwd = Get()) { - if (selection == FullSelection) { - auto fwdinfo = fwd->_text.originalTextWithEntities(AllTextSelection, ExpandLinksAll); - TextWithEntities wrapped; - wrapped.text.reserve(fwdinfo.text.size() + 4 + result.text.size()); - wrapped.entities.reserve(fwdinfo.entities.size() + result.entities.size()); - wrapped.text.append('['); - appendTextWithEntities(wrapped, std_::move(fwdinfo)); - wrapped.text.append(qsl("]\n")); - appendTextWithEntities(wrapped, std_::move(result)); - result = wrapped; - } - } - if (auto reply = Get()) { - if (selection == FullSelection && reply->replyToMsg) { - TextWithEntities wrapped; - wrapped.text.reserve(lang(lng_in_reply_to).size() + reply->replyToMsg->author()->name.size() + 4 + result.text.size()); - wrapped.text.append('[').append(lang(lng_in_reply_to)).append(' ').append(reply->replyToMsg->author()->name).append(qsl("]\n")); - appendTextWithEntities(wrapped, std_::move(result)); - result = wrapped; - } - } - return result; -} - -void HistoryMessage::setMedia(const MTPMessageMedia *media) { - if (!_media && (!media || media->type() == mtpc_messageMediaEmpty)) return; - - bool mediaRemovedSkipBlock = false; - if (_media) { - mediaRemovedSkipBlock = _media->isDisplayed() && !_media->isAboveMessage(); - _media.clear(); - } - QString t; - initMedia(media, t); - if (_media && _media->isDisplayed() && !_media->isAboveMessage() && !mediaRemovedSkipBlock) { - _text.removeSkipBlock(); - _textWidth = -1; - _textHeight = 0; - } else if (mediaRemovedSkipBlock && (!_media || !_media->isDisplayed() || _media->isAboveMessage())) { - _text.setSkipBlock(skipBlockWidth(), skipBlockHeight()); - _textWidth = -1; - _textHeight = 0; - } -} - -void HistoryMessage::setText(const TextWithEntities &textWithEntities) { - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - if (_media && _media->isDisplayed() && !_media->isAboveMessage()) { - _text.setMarkedText(st::msgFont, textWithEntities, itemTextOptions(this)); - } else { - _text.setMarkedText(st::msgFont, { textWithEntities.text + skipBlock(), textWithEntities.entities }, itemTextOptions(this)); - } - textstyleRestore(); - - for_const (auto &entity, textWithEntities.entities) { - auto type = entity.type(); - if (type == EntityInTextUrl || type == EntityInTextCustomUrl || type == EntityInTextEmail) { - _flags |= MTPDmessage_ClientFlag::f_has_text_links; - break; - } - } - _textWidth = -1; - _textHeight = 0; -} - -void HistoryMessage::setEmptyText() { - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - _text.setMarkedText(st::msgFont, { QString(), EntitiesInText() }, itemTextOptions(this)); - textstyleRestore(); - - _textWidth = -1; - _textHeight = 0; -} - -void HistoryMessage::setReplyMarkup(const MTPReplyMarkup *markup) { - if (!markup) { - if (_flags & MTPDmessage::Flag::f_reply_markup) { - _flags &= ~MTPDmessage::Flag::f_reply_markup; - if (Has()) { - RemoveComponents(HistoryMessageReplyMarkup::Bit()); - } - setPendingInitDimensions(); - Notify::replyMarkupUpdated(this); - } - return; - } - - // 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) { - bool changed = false; - if (Has()) { - RemoveComponents(HistoryMessageReplyMarkup::Bit()); - changed = true; - } - if (!(_flags & MTPDmessage::Flag::f_reply_markup)) { - _flags |= MTPDmessage::Flag::f_reply_markup; - changed = true; - } - if (changed) { - setPendingInitDimensions(); - - Notify::replyMarkupUpdated(this); - } - } else { - if (!(_flags & MTPDmessage::Flag::f_reply_markup)) { - _flags |= MTPDmessage::Flag::f_reply_markup; - } - if (!Has()) { - AddComponents(HistoryMessageReplyMarkup::Bit()); - } - Get()->create(*markup); - setPendingInitDimensions(); - - Notify::replyMarkupUpdated(this); - } -} - -TextWithEntities HistoryMessage::originalText() const { - if (emptyText()) { - return { QString(), EntitiesInText() }; - } - return _text.originalTextWithEntities(); -} - -bool HistoryMessage::textHasLinks() const { - return emptyText() ? false : _text.hasLinks(); -} - -void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const { - p.setFont(st::msgDateFont); - - bool outbg = out() && !isPost(); - bool invertedsprites = (type == InfoDisplayOverImage || type == InfoDisplayOverBackground); - int32 infoRight = right, infoBottom = bottom; - switch (type) { - case InfoDisplayDefault: - infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); - infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); - p.setPen(selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); - break; - case InfoDisplayOverImage: - infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); - infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); - p.setPen(st::msgDateImgColor); - break; - case InfoDisplayOverBackground: - infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); - infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); - p.setPen(st::msgServiceColor); - break; - } - - int32 infoW = HistoryMessage::infoWidth(); - if (rtl()) infoRight = width - infoRight + infoW; - - int32 dateX = infoRight - infoW; - int32 dateY = infoBottom - st::msgDateFont->height; - if (type == InfoDisplayOverImage) { - int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); - App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); - } else if (type == InfoDisplayOverBackground) { - int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); - App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? App::msgServiceSelectBg() : App::msgServiceBg(), selected ? StickerSelectedCorners : StickerCorners); - } - dateX += HistoryMessage::timeLeft(); - - if (auto msgsigned = Get()) { - msgsigned->_signature.drawElided(p, dateX, dateY, _timeWidth); - } else if (auto edited = Get()) { - edited->_edited.drawElided(p, dateX, dateY, _timeWidth); - } else { - p.drawText(dateX, dateY + st::msgDateFont->ascent, _timeText); - } - - QPoint iconPos; - const style::sprite *iconRect = nullptr; - if (auto views = Get()) { - iconPos = QPoint(infoRight - infoW + st::msgViewsPos.x(), infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); - if (id > 0) { - if (outbg) { - iconRect = &(invertedsprites ? st::msgInvViewsImg : (selected ? st::msgSelectOutViewsImg : st::msgOutViewsImg)); - } else { - iconRect = &(invertedsprites ? st::msgInvViewsImg : (selected ? st::msgSelectViewsImg : st::msgViewsImg)); - } - p.drawText(iconPos.x() + st::msgViewsImg.pxWidth() + st::msgDateCheckSpace, infoBottom - st::msgDateFont->descent, views->_viewsText); - } else { - iconPos.setX(iconPos.x() + st::msgDateViewsSpace + views->_viewsWidth); - if (outbg) { - iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingOutViewsImg); - } else { - iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); - } - } - p.drawSprite(iconPos, *iconRect); - } else if (id < 0 && history()->peer->isSelf()) { - iconPos = QPoint(infoRight - infoW, infoBottom - st::msgViewsImg.pxHeight() + st::msgViewsPos.y()); - iconRect = &(invertedsprites ? st::msgInvSendingViewsImg : st::msgSendingViewsImg); - p.drawSprite(iconPos, *iconRect); - } - if (outbg) { - iconPos = QPoint(infoRight - st::msgCheckImg.pxWidth() + st::msgCheckPos.x(), infoBottom - st::msgCheckImg.pxHeight() + st::msgCheckPos.y()); - if (id > 0) { - if (unread()) { - iconRect = &(invertedsprites ? st::msgInvCheckImg : (selected ? st::msgSelectCheckImg : st::msgCheckImg)); - } else { - iconRect = &(invertedsprites ? st::msgInvDblCheckImg : (selected ? st::msgSelectDblCheckImg : st::msgDblCheckImg)); - } - } else { - iconRect = &(invertedsprites ? st::msgInvSendingImg : st::msgSendingImg); - } - p.drawSprite(iconPos, *iconRect); - } -} - -void HistoryMessage::setViewsCount(int32 count) { - auto views = Get(); - if (!views || views->_views == count || (count >= 0 && views->_views > count)) return; - - int32 was = views->_viewsWidth; - views->_views = count; - views->_viewsText = (views->_views >= 0) ? formatViewsCount(views->_views) : QString(); - views->_viewsWidth = views->_viewsText.isEmpty() ? 0 : st::msgDateFont->width(views->_viewsText); - if (was == views->_viewsWidth) { - Ui::repaintHistoryItem(this); - } else { - if (_text.hasSkipBlock()) { - _text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight()); - _textWidth = -1; - _textHeight = 0; - } - setPendingInitDimensions(); - } -} - -void HistoryMessage::setId(MsgId newId) { - bool wasPositive = (id > 0), positive = (newId > 0); - HistoryItem::setId(newId); - if (wasPositive == positive) { - Ui::repaintHistoryItem(this); - } else { - if (_text.hasSkipBlock()) { - _text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight()); - _textWidth = -1; - _textHeight = 0; - } - setPendingInitDimensions(); - } -} - -void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - bool outbg = out() && !isPost(), bubble = drawBubble(), selected = (selection == FullSelection); - - int left = 0, width = 0, height = _height; - countPositionAndSize(left, width); - if (width < 1) return; - - int dateh = 0, unreadbarh = 0; - if (auto date = Get()) { - dateh = date->height(); - //if (r.intersects(QRect(0, 0, _history->width, dateh))) { - // date->paint(p, 0, _history->width); - //} - } - if (auto unreadbar = Get()) { - unreadbarh = unreadbar->height(); - if (r.intersects(QRect(0, dateh, _history->width, unreadbarh))) { - p.translate(0, dateh); - unreadbar->paint(p, 0, _history->width); - p.translate(0, -dateh); - } - } - - uint64 fullAnimMs = App::main() ? App::main()->animActiveTimeStart(this) : 0; - if (fullAnimMs > 0 && fullAnimMs <= ms) { - int animms = ms - fullAnimMs; - if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { - App::main()->stopAnimActive(); - } else { - int skiph = marginTop() - marginBottom(); - - float64 dt = (animms > st::activeFadeInDuration) ? (1 - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration)); - float64 o = p.opacity(); - p.setOpacity(o * dt); - p.fillRect(0, skiph, _history->width, height - skiph, textstyleCurrent()->selectOverlay->b); - p.setOpacity(o); - } - } - - textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); - - if (auto keyboard = inlineReplyKeyboard()) { - int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); - height -= h; - int top = height + st::msgBotKbButton.margin - marginBottom(); - p.translate(left, top); - keyboard->paint(p, r.translated(-left, -top)); - p.translate(-left, -top); - } - - if (bubble) { - if (displayFromName() && author()->nameVersion > _authorNameVersion) { - fromNameUpdated(width); - } - - int32 top = marginTop(); - QRect r(left, top, width, height - top - marginBottom()); - - style::color bg(selected ? (outbg ? st::msgOutBgSelected : st::msgInBgSelected) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutShadowSelected : st::msgInShadowSelected) : (outbg ? st::msgOutShadow : st::msgInShadow)); - RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); - App::roundRect(p, r, bg, cors, &sh); - - QRect trect(r.marginsAdded(-st::msgPadding)); - paintFromName(p, trect, selected); - paintForwardedInfo(p, trect, selected); - paintReplyInfo(p, trect, selected); - paintViaBotIdInfo(p, trect, selected); - - auto needDrawInfo = true; - if (_media && _media->isDisplayed()) { - auto mediaAboveText = _media->isAboveMessage(); - auto mediaHeight = _media->height(); - auto mediaLeft = trect.x() - st::msgPadding.left(); - auto mediaTop = mediaAboveText ? (trect.y() - st::msgPadding.top()) : (r.y() + r.height() - mediaHeight); - if (!mediaAboveText) { - paintText(p, trect, selection); - } - p.translate(mediaLeft, mediaTop); - _media->draw(p, r.translated(-mediaLeft, -mediaTop), toMediaSelection(selection), ms); - p.translate(-mediaLeft, -mediaTop); - - if (mediaAboveText) { - trect.setY(trect.y() + mediaHeight); - paintText(p, trect, selection); - } - - needDrawInfo = !_media->customInfoLayout(); - } else { - paintText(p, trect, selection); - } - if (needDrawInfo) { - HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); - } - } else if (_media) { - int32 top = marginTop(); - p.translate(left, top); - _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); - p.translate(-left, -top); - } - - textstyleRestore(); - - auto reply = Get(); - if (reply && reply->isNameUpdated()) { - const_cast(this)->setPendingInitDimensions(); - } -} - -void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const { - if (displayFromName()) { - p.setFont(st::msgNameFont); - if (isPost()) { - p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); - } else { - p.setPen(author()->color); - } - author()->nameText.drawElided(p, trect.left(), trect.top(), trect.width()); - - auto fwd = Get(); - auto via = Get(); - if (via && !fwd && trect.width() > author()->nameText.maxWidth() + st::msgServiceFont->spacew) { - bool outbg = out() && !isPost(); - p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); - p.drawText(trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, trect.top() + st::msgServiceFont->ascent, via->_text); - } - trect.setY(trect.y() + st::msgNameFont->height); - } -} - -void HistoryMessage::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const { - if (displayForwardedFrom()) { - style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont); - - p.setPen(selected ? (hasOutLayout() ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (hasOutLayout() ? st::msgOutServiceFg : st::msgInServiceFg)); - p.setFont(serviceFont); - - auto fwd = Get(); - bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * serviceFont->height); - textstyleSet(&(selected ? (hasOutLayout() ? st::outFwdTextStyleSelected : st::inFwdTextStyleSelected) : (hasOutLayout() ? st::outFwdTextStyle : st::inFwdTextStyle))); - fwd->_text.drawElided(p, trect.x(), trect.y(), trect.width(), 2, style::al_left, 0, -1, 0, breakEverywhere); - textstyleSet(&(hasOutLayout() ? st::outTextStyle : st::inTextStyle)); - - trect.setY(trect.y() + (((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * serviceFont->height)); - } -} - -void HistoryMessage::paintReplyInfo(Painter &p, QRect &trect, bool selected) const { - if (auto reply = Get()) { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - - HistoryMessageReply::PaintFlags flags = HistoryMessageReply::PaintInBubble; - if (selected) { - flags |= HistoryMessageReply::PaintSelected; - } - reply->paint(p, this, trect.x(), trect.y(), trect.width(), flags); - - trect.setY(trect.y() + h); - } -} - -void HistoryMessage::paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const { - if (!displayFromName() && !Has()) { - if (auto via = Get()) { - p.setFont(st::msgServiceNameFont); - p.setPen(selected ? (hasOutLayout() ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (hasOutLayout() ? st::msgOutServiceFg : st::msgInServiceFg)); - p.drawTextLeft(trect.left(), trect.top(), _history->width, via->_text); - trect.setY(trect.y() + st::msgServiceNameFont->height); - } - } -} - -void HistoryMessage::paintText(Painter &p, QRect &trect, TextSelection selection) const { - p.setPen(st::msgColor); - p.setFont(st::msgFont); - _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection); -} - -void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) { - if (auto reply = Get()) { - reply->itemRemoved(this, dependency); - } -} - -int HistoryMessage::resizeGetHeight_(int width) { - int result = performResizeGetHeight(width); - - auto keyboard = inlineReplyKeyboard(); - if (auto markup = Get()) { - int oldTop = markup->oldTop; - if (oldTop >= 0) { - markup->oldTop = -1; - if (keyboard) { - int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); - int keyboardTop = _height - h + st::msgBotKbButton.margin - marginBottom(); - if (keyboardTop != oldTop) { - Notify::inlineKeyboardMoved(this, oldTop, keyboardTop); - } - } - } - } - - return result; -} - -int HistoryMessage::performResizeGetHeight(int width) { - if (width < st::msgMinWidth) return _height; - - width -= st::msgMargin.left() + st::msgMargin.right(); - if (width < st::msgPadding.left() + st::msgPadding.right() + 1) { - width = st::msgPadding.left() + st::msgPadding.right() + 1; - } else if (width > st::msgMaxWidth) { - width = st::msgMaxWidth; - } - if (drawBubble()) { - auto fwd = Get(); - auto reply = Get(); - auto via = Get(); - - bool media = (_media && _media->isDisplayed()); - if (width >= _maxw) { - _height = _minh; - if (media) _media->resizeGetHeight(_maxw); - } else { - if (emptyText()) { - _height = 0; - } else { - int32 textWidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 1); - if (textWidth != _textWidth) { - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - _textWidth = textWidth; - _textHeight = _text.countHeight(textWidth); - textstyleRestore(); - } - _height = st::msgPadding.top() + _textHeight + st::msgPadding.bottom(); - } - if (media) _height += _media->resizeGetHeight(width); - } - - auto mediaTopPaddingAdded = !emptyText(); - if (displayFromName()) { - int32 l = 0, w = 0; - countPositionAndSize(l, w); - fromNameUpdated(w); - - if (!mediaTopPaddingAdded) { - _height += st::msgPadding.top() + st::mediaHeaderSkip; - mediaTopPaddingAdded = true; - } - _height += st::msgNameFont->height; - } else if (via && !fwd) { - int32 l = 0, w = 0; - countPositionAndSize(l, w); - via->resize(w - st::msgPadding.left() - st::msgPadding.right()); - - if (!mediaTopPaddingAdded) { - _height += st::msgPadding.top() + st::mediaHeaderSkip; - mediaTopPaddingAdded = true; - } - _height += st::msgNameFont->height; - } - - if (displayForwardedFrom()) { - int32 l = 0, w = 0; - countPositionAndSize(l, w); - int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height; - - if (!mediaTopPaddingAdded) { - _height += st::msgPadding.top() + st::mediaHeaderSkip; - mediaTopPaddingAdded = true; - } - _height += fwdheight; - } - - if (reply) { - int32 l = 0, w = 0; - countPositionAndSize(l, w); - reply->resize(w - st::msgPadding.left() - st::msgPadding.right()); - - if (!mediaTopPaddingAdded) { - _height += st::msgPadding.top() + st::mediaHeaderSkip; - mediaTopPaddingAdded = true; - } - _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - } - } else if (_media) { - _height = _media->resizeGetHeight(width); - } else { - _height = 0; - } - if (auto keyboard = inlineReplyKeyboard()) { - int32 l = 0, w = 0; - countPositionAndSize(l, w); - - int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); - _height += h; - keyboard->resize(w, h - st::msgBotKbButton.margin); - } - - _height += marginTop() + marginBottom(); - return _height; -} - -bool HistoryMessage::hasPoint(int x, int y) const { - int left = 0, width = 0, height = _height; - countPositionAndSize(left, width); - if (width < 1) return false; - - if (drawBubble()) { - int top = marginTop(); - QRect r(left, top, width, height - top - marginBottom()); - return r.contains(x, y); - } else if (_media) { - return _media->hasPoint(x - left, y - marginTop()); - } else { - return false; - } -} - -bool HistoryMessage::pointInTime(int32 right, int32 bottom, int x, int y, InfoDisplayType type) const { - int32 infoRight = right, infoBottom = bottom; - switch (type) { - case InfoDisplayDefault: - infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); - infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); - break; - case InfoDisplayOverImage: - infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); - infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); - break; - } - int32 dateX = infoRight - HistoryMessage::infoWidth() + HistoryMessage::timeLeft(); - int32 dateY = infoBottom - st::msgDateFont->height; - return QRect(dateX, dateY, HistoryMessage::timeWidth(), st::msgDateFont->height).contains(x, y); -} - -HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - int left = 0, width = 0, height = _height; - countPositionAndSize(left, width); - - if (width < 1) return result; - - auto keyboard = inlineReplyKeyboard(); - if (keyboard) { - int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); - height -= h; - } - - if (drawBubble()) { - auto fwd = Get(); - auto via = Get(); - auto reply = Get(); - - int top = marginTop(); - QRect r(left, top, width, height - top - marginBottom()); - QRect trect(r.marginsAdded(-st::msgPadding)); - if (displayFromName()) { - if (y >= trect.top() && y < trect.top() + st::msgNameFont->height) { - if (x >= trect.left() && x < trect.left() + trect.width() && x < trect.left() + author()->nameText.maxWidth()) { - result.link = author()->openLink(); - return result; - } - if (via && !fwd && x >= trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) { - result.link = via->_lnk; - return result; - } - } - trect.setTop(trect.top() + st::msgNameFont->height); - } - if (displayForwardedFrom()) { - int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; - if (y >= trect.top() && y < trect.top() + fwdheight) { - bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * st::semiboldFont->height); - auto textRequest = request.forText(); - if (breakEverywhere) { - textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere; - } - textstyleSet(&st::inFwdTextStyle); - result = fwd->_text.getState(x - trect.left(), y - trect.top(), trect.width(), textRequest); - textstyleRestore(); - result.symbol = 0; - result.afterSymbol = false; - if (breakEverywhere) { - result.cursor = HistoryInForwardedCursorState; - } else { - result.cursor = HistoryDefaultCursorState; - } - return result; - } - trect.setTop(trect.top() + fwdheight); - } - if (reply) { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - if (y >= trect.top() && y < trect.top() + h) { - if (reply->replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) { - result.link = reply->replyToLink(); - } - return result; - } - trect.setTop(trect.top() + h); - } - if (via && !displayFromName() && !displayForwardedFrom()) { - if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) { - result.link = via->_lnk; - return result; - } - trect.setTop(trect.top() + st::msgNameFont->height); - } - - bool inDate = false, mediaDisplayed = _media && _media->isDisplayed(); - if (!mediaDisplayed || !_media->customInfoLayout()) { - inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); - } - - if (mediaDisplayed) { - trect.setBottom(trect.bottom() - _media->height()); - if (y >= r.bottom() - _media->height()) { - result = _media->getState(x - r.left(), y - (r.bottom() - _media->height()), request); - result.symbol += _text.length(); - } - } - if (!mediaDisplayed || (y < r.bottom() - _media->height())) { - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), request.forText()); - textstyleRestore(); - } - if (inDate) { - result.cursor = HistoryInDateCursorState; - } - } else if (_media) { - result = _media->getState(x - left, y - marginTop(), request); - result.symbol += _text.length(); - } - - if (keyboard) { - int top = height + st::msgBotKbButton.margin - marginBottom(); - if (x >= left && x < left + width && y >= top && y < _height - marginBottom()) { - result.link = keyboard->getState(x - left, y - top); - return result; - } - } - - return result; -} - -TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelectType type) const { - if (!_media || selection.to <= _text.length()) { - return _text.adjustSelection(selection, type); - } - auto mediaSelection = _media->adjustSelection(toMediaSelection(selection), type); - if (selection.from >= _text.length()) { - return fromMediaSelection(mediaSelection); - } - auto textSelection = _text.adjustSelection(selection, type); - return { textSelection.from, fromMediaSelection(mediaSelection).to }; -} - -QString HistoryMessage::notificationHeader() const { - return (!_history->peer->isUser() && !isPost()) ? from()->name : QString(); -} - -bool HistoryMessage::displayFromPhoto() const { - return hasFromPhoto() && !isAttachedToPrevious(); -} - -bool HistoryMessage::hasFromPhoto() const { - return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty(); -} - -HistoryMessage::~HistoryMessage() { - _media.clear(); - if (auto reply = Get()) { - reply->clearData(this); - } -} - -void HistoryService::setMessageByAction(const MTPmessageAction &action) { - auto text = lang(lng_message_empty); - auto from = textcmdLink(1, _from->name); - - Links links; - links.push_back(MakeShared(_from)); - - switch (action.type()) { - case mtpc_messageActionChatAddUser: { - auto &d = action.c_messageActionChatAddUser(); - auto &v = d.vusers.c_vector().v; - bool foundSelf = false; - for (int i = 0, l = v.size(); i < l; ++i) { - if (v.at(i).v == MTP::authedId()) { - foundSelf = true; - break; - } - } - if (v.size() == 1) { - auto u = App::user(peerFromUser(v.at(0))); - if (u == _from) { - text = lng_action_user_joined(lt_from, from); - } else { - links.push_back(MakeShared(u)); - text = lng_action_add_user(lt_from, from, lt_user, textcmdLink(2, u->name)); - } - } else if (v.isEmpty()) { - text = lng_action_add_user(lt_from, from, lt_user, "somebody"); - } else { - for (int i = 0, l = v.size(); i < l; ++i) { - auto u = App::user(peerFromUser(v.at(i))); - auto linkText = textcmdLink(i + 2, u->name); - if (i == 0) { - text = linkText; - } else if (i + 1 < l) { - text = lng_action_add_users_and_one(lt_accumulated, text, lt_user, linkText); - } else { - text = lng_action_add_users_and_last(lt_accumulated, text, lt_user, linkText); - } - links.push_back(MakeShared(u)); - } - text = lng_action_add_users_many(lt_from, from, lt_users, text); - } - if (foundSelf) { - if (history()->peer->isMegagroup()) { - history()->peer->asChannel()->mgInfo->joinedMessageFound = true; - } - } - } break; - - case mtpc_messageActionChatJoinedByLink: { - auto &d = action.c_messageActionChatJoinedByLink(); - //if (true || peerFromUser(d.vinviter_id) == _from->id) { - text = lng_action_user_joined_by_link(lt_from, from); - //} else { - // UserData *u = App::user(App::peerFromUser(d.vinviter_id)); - // links.push_back(MakeShared(u)); - // text = lng_action_user_joined_by_link_from(lt_from, from, lt_inviter, textcmdLink(2, u->name)); - //} - if (_from->isSelf() && history()->peer->isMegagroup()) { - history()->peer->asChannel()->mgInfo->joinedMessageFound = true; - } - } break; - - case mtpc_messageActionChatCreate: { - auto &d = action.c_messageActionChatCreate(); - text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle))); - } break; - - case mtpc_messageActionChannelCreate: { - auto &d = action.c_messageActionChannelCreate(); - if (isPost()) { - text = lng_action_created_channel(lt_title, textClean(qs(d.vtitle))); - } else { - text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle))); - } - } break; - - case mtpc_messageActionHistoryClear: { - text = QString(); - } break; - - case mtpc_messageActionChatDeletePhoto: { - text = isPost() ? lang(lng_action_removed_photo_channel) : lng_action_removed_photo(lt_from, from); - } break; - - case mtpc_messageActionChatDeleteUser: { - auto &d = action.c_messageActionChatDeleteUser(); - if (peerFromUser(d.vuser_id) == _from->id) { - text = lng_action_user_left(lt_from, from); - } else { - auto u = App::user(peerFromUser(d.vuser_id)); - links.push_back(MakeShared(u)); - text = lng_action_kick_user(lt_from, from, lt_user, textcmdLink(2, u->name)); - } - } break; - - case mtpc_messageActionChatEditPhoto: { - auto &d = action.c_messageActionChatEditPhoto(); - if (d.vphoto.type() == mtpc_photo) { - _media.reset(new HistoryPhoto(this, history()->peer, d.vphoto.c_photo(), st::msgServicePhotoWidth)); - } - text = isPost() ? lang(lng_action_changed_photo_channel) : lng_action_changed_photo(lt_from, from); - } break; - - case mtpc_messageActionChatEditTitle: { - auto &d = action.c_messageActionChatEditTitle(); - text = isPost() ? lng_action_changed_title_channel(lt_title, textClean(qs(d.vtitle))) : lng_action_changed_title(lt_from, from, lt_title, textClean(qs(d.vtitle))); - } break; - - case mtpc_messageActionChatMigrateTo: { - _flags |= MTPDmessage_ClientFlag::f_is_group_migrate; - auto &d = action.c_messageActionChatMigrateTo(); - if (true/*PeerData *channel = App::channelLoaded(d.vchannel_id.v)*/) { - text = lang(lng_action_group_migrate); - } else { - text = lang(lng_contacts_loading); - } - } break; - - case mtpc_messageActionChannelMigrateFrom: { - _flags |= MTPDmessage_ClientFlag::f_is_group_migrate; - auto &d = action.c_messageActionChannelMigrateFrom(); - if (true/*PeerData *chat = App::chatLoaded(d.vchat_id.v)*/) { - text = lang(lng_action_group_migrate); - } else { - text = lang(lng_contacts_loading); - } - } break; - - case mtpc_messageActionPinMessage: { - preparePinnedText(from, &text, &links); - } break; - - case mtpc_messageActionGameScore: { - prepareGameScoreText(from, &text, &links); - } break; - - default: from = QString(); break; - } - - setServiceText(text, links); - for (int i = 0, count = links.size(); i != count; ++i) { - _text.setLink(1 + i, links.at(i)); - } -} - -bool HistoryService::updateDependent(bool force) { - auto dependent = GetDependentData(); - t_assert(dependent != nullptr); - - if (!force) { - if (!dependent->msgId || dependent->msg) { - return true; - } - } - - if (!dependent->lnk) { - dependent->lnk.reset(new GoToMessageClickHandler(history()->peer->id, dependent->msgId)); - } - bool gotDependencyItem = false; - if (!dependent->msg) { - dependent->msg = App::histItemById(channelId(), dependent->msgId); - if (dependent->msg) { - App::historyRegDependency(this, dependent->msg); - gotDependencyItem = true; - } - } - if (dependent->msg) { - updateDependentText(); - } else if (force) { - if (dependent->msgId > 0) { - dependent->msgId = 0; - gotDependencyItem = true; - } - updateDependentText(); - } - if (force) { - if (gotDependencyItem && App::wnd()) { - App::wnd()->notifySettingGot(); - } - } - return (dependent->msg || !dependent->msgId); -} - -bool HistoryService::preparePinnedText(const QString &from, QString *outText, Links *outLinks) { - bool result = false; - QString text; - - ClickHandlerPtr second; - auto pinned = Get(); - if (pinned && pinned->msg) { - HistoryMedia *media = pinned->msg->getMedia(); - QString mediaText; - switch (media ? media->type() : MediaTypeCount) { - case MediaTypePhoto: mediaText = lang(lng_action_pinned_media_photo); break; - case MediaTypeVideo: mediaText = lang(lng_action_pinned_media_video); break; - case MediaTypeContact: mediaText = lang(lng_action_pinned_media_contact); break; - case MediaTypeFile: mediaText = lang(lng_action_pinned_media_file); break; - case MediaTypeGif: mediaText = lang(lng_action_pinned_media_gif); break; - case MediaTypeSticker: mediaText = lang(lng_action_pinned_media_sticker); break; - case MediaTypeLocation: mediaText = lang(lng_action_pinned_media_location); break; - case MediaTypeMusicFile: mediaText = lang(lng_action_pinned_media_audio); break; - case MediaTypeVoiceFile: mediaText = lang(lng_action_pinned_media_voice); break; - } - if (mediaText.isEmpty()) { - QString original = pinned->msg->originalText().text; - int32 cutat = 0, limit = PinnedMessageTextLimit, size = original.size(); - for (; limit > 0;) { - --limit; - if (cutat >= size) break; - if (original.at(cutat).isLowSurrogate() && cutat + 1 < size && original.at(cutat + 1).isHighSurrogate()) { - cutat += 2; - } else { - ++cutat; - } - } - if (!limit && cutat + 5 < size) { - original = original.mid(0, cutat) + qstr("..."); - } - text = lng_action_pinned_message(lt_from, from, lt_text, textcmdLink(2, original)); - } else { - text = lng_action_pinned_media(lt_from, from, lt_media, textcmdLink(2, mediaText)); - } - second = pinned->lnk; - result = true; - } else if (pinned && pinned->msgId) { - text = lng_action_pinned_media(lt_from, from, lt_media, textcmdLink(2, lang(lng_contacts_loading))); - second = pinned->lnk; - result = true; - } else { - text = lng_action_pinned_media(lt_from, from, lt_media, lang(lng_deleted_message)); - } - *outText = text; - if (second) { - outLinks->push_back(second); - } - return result; -} - -bool HistoryService::prepareGameScoreText(const QString &from, QString *outText, Links *outLinks) { - bool result = false; - QString text; - - ClickHandlerPtr second; - auto gamescore = Get(); - if (gamescore && gamescore->msg) { - auto getGameTitle = [item = gamescore->msg, &second]() -> QString { - if (auto media = item->getMedia()) { - if (media->type() == MediaTypeGame) { - return static_cast(media)->game()->title; - } - } - return lang(lng_deleted_message); - }; - text = lng_action_game_score(lt_from, from, lt_count, gamescore->score, lt_game, getGameTitle()); - result = true; - } else if (gamescore && gamescore->msgId) { - text = lng_action_game_score(lt_from, from, lt_count, gamescore->score, lt_game, lang(lng_contacts_loading)); - result = true; - } else { - text = lng_action_game_score(lt_from, from, lt_count, gamescore->score, lt_game, lang(lng_deleted_message)); - } - *outText = text; - if (second) { - outLinks->push_back(second); - } - return result; -} - -HistoryService::HistoryService(History *history, const MTPDmessageService &msg) : - HistoryItem(history, msg.vid.v, mtpCastFlags(msg.vflags.v), ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { - createFromMtp(msg); - setMessageByAction(msg.vaction); -} - -HistoryService::HistoryService(History *history, MsgId msgId, QDateTime date, const QString &msg, MTPDmessage::Flags flags, int32 from) : - HistoryItem(history, msgId, flags, date, from) { - setServiceText(msg, Links()); -} - -void HistoryService::initDimensions() { - _maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right(); - _minh = _text.minHeight(); - if (_media) _media->initDimensions(); -} - -bool HistoryService::updateDependencyItem() { - if (GetDependentData()) { - return updateDependent(true); - } - return HistoryItem::updateDependencyItem(); -} - -void HistoryService::countPositionAndSize(int32 &left, int32 &width) const { - left = st::msgServiceMargin.left(); - int32 maxwidth = _history->width; - if (Adaptive::Wide()) { - maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); - } - width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); -} - -TextWithEntities HistoryService::selectedText(TextSelection selection) const { - return _text.originalTextWithEntities((selection == FullSelection) ? AllTextSelection : selection); -} - -QString HistoryService::inDialogsText() const { - return textcmdLink(1, textClean(notificationText())); -} - -QString HistoryService::inReplyText() const { - QString result = HistoryService::notificationText(); - return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result; -} - -void HistoryService::setServiceText(const QString &text, const Links &links) { - textstyleSet(&st::serviceTextStyle); - _text.setText(st::msgServiceFont, text, _historySrvOptions); - textstyleRestore(); - for (int i = 0, count = links.size(); i != count; ++i) { - _text.setLink(1 + i, links.at(i)); - } - - setPendingInitDimensions(); - _textWidth = -1; - _textHeight = 0; -} - -void HistoryService::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { - int height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); - - QRect clip(r); - int dateh = 0, unreadbarh = 0; - if (auto date = Get()) { - dateh = date->height(); - //if (clip.intersects(QRect(0, 0, _history->width, dateh))) { - // date->paint(p, 0, _history->width); - //} - p.translate(0, dateh); - clip.translate(0, -dateh); - height -= dateh; - } - if (auto unreadbar = Get()) { - unreadbarh = unreadbar->height(); - if (clip.intersects(QRect(0, 0, _history->width, unreadbarh))) { - unreadbar->paint(p, 0, _history->width); - } - p.translate(0, unreadbarh); - clip.translate(0, -unreadbarh); - height -= unreadbarh; - } - - HistoryLayout::PaintContext context(ms, clip, selection); - HistoryLayout::ServiceMessagePainter::paint(p, this, context, height); - - if (int skiph = dateh + unreadbarh) { - p.translate(0, -skiph); - } -} - -int32 HistoryService::resizeGetHeight_(int32 width) { - _height = displayedDateHeight(); - if (auto unreadbar = Get()) { - _height += unreadbar->height(); - } - - if (_text.isEmpty()) { - _textHeight = 0; - } else { - int32 maxwidth = _history->width; - if (Adaptive::Wide()) { - maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); - } - if (width > maxwidth) width = maxwidth; - width -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins - if (width < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) width = st::msgServicePadding.left() + st::msgServicePadding.right() + 1; - - int32 nwidth = qMax(width - st::msgServicePadding.left() - st::msgServicePadding.right(), 0); - if (nwidth != _textWidth) { - _textWidth = nwidth; - textstyleSet(&st::serviceTextStyle); - _textHeight = _text.countHeight(nwidth); - textstyleRestore(); - } - if (width >= _maxw) { - _height += _minh; - } else { - _height += _textHeight; - } - _height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); - if (_media) { - _height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth()); - } - } - - return _height; -} - -bool HistoryService::hasPoint(int x, int y) const { - int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins - countPositionAndSize(left, width); - if (width < 1) return false; - - if (int dateh = displayedDateHeight()) { - y -= dateh; - height -= dateh; - } - if (auto unreadbar = Get()) { - int unreadbarh = unreadbar->height(); - y -= unreadbarh; - height -= unreadbarh; - } - - if (_media) { - height -= st::msgServiceMargin.top() + _media->height(); - } - return QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y); -} - -HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest request) const { - HistoryTextState result; - - int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins - countPositionAndSize(left, width); - if (width < 1) return result; - - if (int dateh = displayedDateHeight()) { - y -= dateh; - height -= dateh; - } - if (auto unreadbar = Get()) { - int unreadbarh = unreadbar->height(); - y -= unreadbarh; - height -= unreadbarh; - } - - if (_media) { - height -= st::msgServiceMargin.top() + _media->height(); - } - auto outer = QRect(left, st::msgServiceMargin.top(), width, height); - auto trect = outer.marginsAdded(-st::msgServicePadding); - if (trect.contains(x, y)) { - textstyleSet(&st::serviceTextStyle); - auto textRequest = request.forText(); - textRequest.align = style::al_center; - result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), textRequest); - textstyleRestore(); - if (auto gamescore = Get()) { - if (!result.link && outer.contains(x, y)) { - result.link = gamescore->lnk; - } - } - } else if (_media) { - result = _media->getState(x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), request); - } - return result; -} - -void HistoryService::createFromMtp(const MTPDmessageService &message) { - if (message.has_reply_to_msg_id()) { - if (message.vaction.type() == mtpc_messageActionPinMessage) { - UpdateComponents(HistoryServicePinned::Bit()); - } else if (message.vaction.type() == mtpc_messageActionGameScore) { - UpdateComponents(HistoryServiceGameScore::Bit()); - Get()->score = message.vaction.c_messageActionGameScore().vscore.v; - } - if (auto dependent = GetDependentData()) { - dependent->msgId = message.vreply_to_msg_id.v; - if (!updateDependent() && App::api()) { - App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId())); - } - } - } - setMessageByAction(message.vaction); -} - -void HistoryService::applyEdition(const MTPDmessageService &message) { - clearDependency(); - UpdateComponents(0); - - createFromMtp(message); - - if (message.vaction.type() == mtpc_messageActionHistoryClear) { - removeMedia(); - finishEditionToEmpty(); - } else { - finishEdition(-1); - } -} - -void HistoryService::removeMedia() { - if (!_media) return; - - bool mediaWasDisplayed = _media->isDisplayed(); - _media.clear(); - if (mediaWasDisplayed) { - _textWidth = -1; - _textHeight = 0; - } -} - -int32 HistoryService::addToOverview(AddToOverviewMethod method) { - if (!indexInOverview()) return 0; - - int32 result = 0; - if (auto media = getMedia()) { - MediaOverviewType type = serviceMediaToOverviewType(media); - if (type != OverviewCount) { - if (history()->addToOverview(type, id, method)) { - result |= (1 << type); - } - } - } - return result; -} - -void HistoryService::eraseFromOverview() { - if (auto media = getMedia()) { - MediaOverviewType type = serviceMediaToOverviewType(media); - if (type != OverviewCount) { - history()->eraseFromOverview(type, id); - } - } -} - -bool HistoryService::updateDependentText() { - auto result = false; - auto from = textcmdLink(1, _from->name); - QString text; - Links links; - links.push_back(MakeShared(_from)); - if (Has()) { - result = preparePinnedText(from, &text, &links); - } else if (Has()) { - result = prepareGameScoreText(from, &text, &links); - } else { - return result; - } - - setServiceText(text, links); - if (history()->textCachedFor == this) { - history()->textCachedFor = 0; - } - if (App::main()) { - App::main()->dlgUpdated(history(), id); - } - App::historyUpdateDependent(this); - return result; -} - -void HistoryService::clearDependency() { - if (auto dependent = GetDependentData()) { - if (dependent->msg) { - App::historyUnregDependency(this, dependent->msg); - } - } -} - -HistoryService::~HistoryService() { - clearDependency(); - _media.clear(); -} - -HistoryJoined::HistoryJoined(History *history, const QDateTime &inviteDate, UserData *inviter, MTPDmessage::Flags flags) - : HistoryService(history, clientMsgId(), inviteDate, QString(), flags) { - Links links; - auto text = ([history, inviter, &links]() { - if (peerToUser(inviter->id) == MTP::authedId()) { - return lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined); - } - links.push_back(MakeShared(inviter)); - if (history->isMegagroup()) { - return lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name)); - } - return lng_action_add_you(lt_from, textcmdLink(1, inviter->name)); - })(); - setServiceText(text, links); -} - -void GoToMessageClickHandler::onClickImpl() const { - if (App::main()) { - HistoryItem *current = App::mousedItem(); - if (current && current->history()->peer->id == peer()) { - App::main()->pushReplyReturn(current); - } - Ui::showPeerHistory(peer(), msgid(), Ui::ShowWay::Forward); - } -} - -void CommentsClickHandler::onClickImpl() const { - if (App::main() && peerIsChannel(peer())) { - Ui::showPeerHistory(peer(), msgid()); - } -} diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 91d1d263ec..02af014529 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -174,7 +174,6 @@ class IndexedList; class ChannelHistory; class History { public: - History(const PeerId &peerId); History(const History &) = delete; History &operator=(const History &) = delete; @@ -390,7 +389,6 @@ protected: void countScrollTopItem(int top); public: - bool lastKeyboardInited = false; bool lastKeyboardUsed = false; MsgId lastKeyboardId = 0; @@ -449,7 +447,6 @@ public: Text cloudDraftTextCache; protected: - void clearOnDestroy(); HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type); @@ -488,7 +485,6 @@ protected: } private: - // After adding a new history slice check the lastMsg and newLoaded. void checkLastMsg(); @@ -552,7 +548,6 @@ private: class HistoryJoined; class ChannelHistory : public History { public: - ChannelHistory(const PeerId &peer); void messageDetached(HistoryItem *msg); @@ -567,7 +562,6 @@ public: ~ChannelHistory(); private: - friend class History; HistoryItem* addNewChannelMessage(const MTPMessage &msg, NewMessageType type); HistoryItem *addNewToBlocks(const MTPMessage &msg, NewMessageType type); @@ -590,7 +584,7 @@ private: class HistoryBlock { public: - HistoryBlock(History *hist) : y(0), height(0), history(hist), _indexInHistory(-1) { + HistoryBlock(History *hist) : history(hist), _indexInHistory(-1) { } HistoryBlock(const HistoryBlock &) = delete; @@ -606,7 +600,8 @@ public: void removeItem(HistoryItem *item); int resizeGetHeight(int newWidth, bool resizeAllItems); - int32 y, height; + int y = 0; + int height = 0; History *history; HistoryBlock *previousBlock() const { @@ -630,2329 +625,6 @@ public: } protected: - int _indexInHistory; }; - -class HistoryElem { -public: - - HistoryElem() : _maxw(0), _minh(0), _height(0) { - } - - int32 maxWidth() const { - return _maxw; - } - int32 minHeight() const { - return _minh; - } - int32 height() const { - return _height; - } - - virtual ~HistoryElem() { - } - -protected: - - mutable int32 _maxw, _minh, _height; - HistoryElem &operator=(const HistoryElem &); - -}; - -class HistoryMessage; - -enum HistoryCursorState { - HistoryDefaultCursorState, - HistoryInTextCursorState, - HistoryInDateCursorState, - HistoryInForwardedCursorState, -}; - -struct HistoryTextState { - HistoryTextState() = default; - HistoryTextState(const Text::StateResult &state) - : cursor(state.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState) - , link(state.link) - , afterSymbol(state.afterSymbol) - , symbol(state.symbol) { - } - HistoryTextState &operator=(const Text::StateResult &state) { - cursor = state.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState; - link = state.link; - afterSymbol = state.afterSymbol; - symbol = state.symbol; - return *this; - } - HistoryCursorState cursor = HistoryDefaultCursorState; - ClickHandlerPtr link; - bool afterSymbol = false; - uint16 symbol = 0; -}; - -struct HistoryStateRequest { - Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink; - Text::StateRequest forText() const { - Text::StateRequest result; - result.flags = flags; - return result; - } -}; - -enum InfoDisplayType { - InfoDisplayDefault, - InfoDisplayOverImage, - InfoDisplayOverBackground, -}; - -enum HistoryItemType { - HistoryItemMsg = 0, - HistoryItemJoined -}; - -struct HistoryMessageVia : public BaseComponent { - void create(int32 userId); - void resize(int32 availw) const; - - UserData *_bot = nullptr; - mutable QString _text; - mutable int _width = 0; - mutable int _maxWidth = 0; - ClickHandlerPtr _lnk; -}; - -struct HistoryMessageViews : public BaseComponent { - QString _viewsText; - int _views = 0; - int _viewsWidth = 0; -}; - -struct HistoryMessageSigned : public BaseComponent { - void create(UserData *from, const QDateTime &date); - int maxWidth() const; - - Text _signature; -}; - -struct HistoryMessageEdited : public BaseComponent { - void create(const QDateTime &editDate, const QDateTime &date); - int maxWidth() const; - - QDateTime _editDate; - Text _edited; -}; - -struct HistoryMessageForwarded : public BaseComponent { - void create(const HistoryMessageVia *via) const; - - PeerData *_authorOriginal = nullptr; - PeerData *_fromOriginal = nullptr; - MsgId _originalId = 0; - mutable Text _text = { 1 }; -}; - -struct HistoryMessageReply : public BaseComponent { - HistoryMessageReply &operator=(HistoryMessageReply &&other) { - replyToMsgId = other.replyToMsgId; - std::swap(replyToMsg, other.replyToMsg); - replyToLnk = std_::move(other.replyToLnk); - replyToName = std_::move(other.replyToName); - replyToText = std_::move(other.replyToText); - replyToVersion = other.replyToVersion; - _maxReplyWidth = other._maxReplyWidth; - _replyToVia = std_::move(other._replyToVia); - return *this; - } - ~HistoryMessageReply() { - // clearData() should be called by holder - t_assert(replyToMsg == nullptr); - t_assert(_replyToVia == nullptr); - } - - bool updateData(HistoryMessage *holder, bool force = false); - void clearData(HistoryMessage *holder); // must be called before destructor - - bool isNameUpdated() const; - void updateName() const; - void resize(int width) const; - void itemRemoved(HistoryMessage *holder, HistoryItem *removed); - - enum PaintFlag { - PaintInBubble = 0x01, - PaintSelected = 0x02, - }; - Q_DECLARE_FLAGS(PaintFlags, PaintFlag); - void paint(Painter &p, const HistoryItem *holder, int x, int y, int w, PaintFlags flags) const; - - MsgId replyToId() const { - return replyToMsgId; - } - int replyToWidth() const { - return _maxReplyWidth; - } - ClickHandlerPtr replyToLink() const { - return replyToLnk; - } - - MsgId replyToMsgId = 0; - HistoryItem *replyToMsg = nullptr; - ClickHandlerPtr replyToLnk; - mutable Text replyToName, replyToText; - mutable int replyToVersion = 0; - mutable int _maxReplyWidth = 0; - std_::unique_ptr _replyToVia; - int toWidth = 0; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(HistoryMessageReply::PaintFlags); - -class ReplyKeyboard; -struct HistoryMessageReplyMarkup : public BaseComponent { - HistoryMessageReplyMarkup() = default; - HistoryMessageReplyMarkup(MTPDreplyKeyboardMarkup::Flags f) : flags(f) { - } - - void create(const MTPReplyMarkup &markup); - - struct Button { - enum class Type { - Default, - Url, - Callback, - RequestPhone, - RequestLocation, - SwitchInline, - SwitchInlineSame, - Game, - }; - Type type; - QString text; - QByteArray data; - mutable mtpRequestId requestId; - }; - using ButtonRow = QVector