From 730412fefe6c3264ec7dc37fb73479014b0af362 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 4 Oct 2021 23:37:55 +0400 Subject: [PATCH] Load albums of last chat messages. --- Telegram/SourceFiles/apiwrap.cpp | 37 +---- Telegram/SourceFiles/apiwrap.h | 1 - Telegram/SourceFiles/data/data_histories.cpp | 43 ++++++ Telegram/SourceFiles/data/data_histories.h | 10 ++ .../SourceFiles/data/data_media_types.cpp | 138 +++++++++--------- Telegram/SourceFiles/data/data_media_types.h | 2 + Telegram/SourceFiles/data/data_session.cpp | 20 +++ Telegram/SourceFiles/data/data_session.h | 3 + .../dialogs/ui/dialogs_message_view.cpp | 12 +- .../dialogs/ui/dialogs_message_view.h | 4 +- Telegram/SourceFiles/history/history.cpp | 74 ++++++++-- Telegram/SourceFiles/history/history.h | 7 + Telegram/SourceFiles/history/history_item.h | 22 ++- .../window/notifications_manager_default.cpp | 2 +- 14 files changed, 253 insertions(+), 122 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index a53718bb4..997ba94f2 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -560,7 +560,8 @@ void ApiWrap::resolveMessageDatas() { )).done([=]( const MTPmessages_Messages &result, mtpRequestId requestId) { - gotMessageDatas(nullptr, result, requestId); + _session->data().processExistingMessages(nullptr, result); + finalizeMessageDataRequest(nullptr, requestId); }).fail([=](const MTP::Error &error, mtpRequestId requestId) { finalizeMessageDataRequest(nullptr, requestId); }).afterDelay(kSmallDelayMs).send(); @@ -586,7 +587,8 @@ void ApiWrap::resolveMessageDatas() { )).done([=]( const MTPmessages_Messages &result, mtpRequestId requestId) { - gotMessageDatas(channel, result, requestId); + _session->data().processExistingMessages(channel, result); + finalizeMessageDataRequest(channel, requestId); }).fail([=](const MTP::Error &error, mtpRequestId requestId) { finalizeMessageDataRequest(channel, requestId); }).afterDelay(kSmallDelayMs).send(); @@ -602,37 +604,6 @@ void ApiWrap::resolveMessageDatas() { } } -void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) { - const auto handleResult = [&](auto &&result) { - _session->data().processUsers(result.vusers()); - _session->data().processChats(result.vchats()); - _session->data().processMessages( - result.vmessages(), - NewMessageType::Existing); - }; - switch (msgs.type()) { - case mtpc_messages_messages: - handleResult(msgs.c_messages_messages()); - break; - case mtpc_messages_messagesSlice: - handleResult(msgs.c_messages_messagesSlice()); - break; - case mtpc_messages_channelMessages: { - auto &d = msgs.c_messages_channelMessages(); - if (channel) { - channel->ptsReceived(d.vpts().v); - } else { - LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)")); - } - handleResult(d); - } break; - case mtpc_messages_messagesNotModified: - LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem)")); - break; - } - finalizeMessageDataRequest(channel, requestId); -} - void ApiWrap::finalizeMessageDataRequest( ChannelData *channel, mtpRequestId requestId) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index afbfa4f45..bd05f9dd1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -458,7 +458,6 @@ private: void saveDraftsToCloud(); void resolveMessageDatas(); - void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId); void finalizeMessageDataRequest( ChannelData *channel, mtpRequestId requestId); diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index ac61bd8f7..eb16e3b99 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -438,6 +438,49 @@ void Histories::requestFakeChatListMessage( }); } +void Histories::requestGroupAround(not_null item) { + const auto history = item->history(); + const auto id = item->id; + const auto i = _chatListGroupRequests.find(history); + if (i != end(_chatListGroupRequests)) { + if (i->second.aroundId == id) { + return; + } else { + cancelRequest(i->second.requestId); + _chatListGroupRequests.erase(i); + } + } + constexpr auto kMaxAlbumCount = 10; + const auto requestId = sendRequest(history, RequestType::History, [=]( + Fn finish) { + return session().api().request(MTPmessages_GetHistory( + history->peer->input, + MTP_int(id), + MTP_int(0), // offset_date + MTP_int(-kMaxAlbumCount), + MTP_int(2 * kMaxAlbumCount - 1), + MTP_int(0), // max_id + MTP_int(0), // min_id + MTP_long(0) // hash + )).done([=](const MTPmessages_Messages &result) { + _owner->processExistingMessages( + history->peer->asChannel(), + result); + _chatListGroupRequests.remove(history); + history->migrateToOrMe()->applyChatListGroup( + history->channelId(), + result); + finish(); + }).fail([=](const MTP::Error &error) { + _chatListGroupRequests.remove(history); + finish(); + }).send(); + }); + _chatListGroupRequests.emplace( + history, + ChatListGroupRequest{ .aroundId = id, .requestId = requestId }); +} + void Histories::sendPendingReadInbox(not_null history) { if (const auto state = lookup(history)) { DEBUG_LOG(("Reading: send pending now with till %1 and when %2" diff --git a/Telegram/SourceFiles/data/data_histories.h b/Telegram/SourceFiles/data/data_histories.h index eca1c07e5..81e9fd1fa 100644 --- a/Telegram/SourceFiles/data/data_histories.h +++ b/Telegram/SourceFiles/data/data_histories.h @@ -59,6 +59,8 @@ public: void changeDialogUnreadMark(not_null history, bool unread); void requestFakeChatListMessage(not_null history); + void requestGroupAround(not_null item); + void deleteMessages( not_null history, const QVector &ids, @@ -95,6 +97,10 @@ private: bool sentReadDone = false; bool postponedRequestEntry = false; }; + struct ChatListGroupRequest { + MsgId aroundId = 0; + mtpRequestId requestId = 0; + }; void readInboxTill(not_null history, MsgId tillId, bool force); void sendReadRequests(); @@ -130,6 +136,10 @@ private: base::flat_set> _fakeChatListRequests; + base::flat_map< + not_null, + ChatListGroupRequest> _chatListGroupRequests; + }; } // namespace Data diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index a3158a2d1..98e757387 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -63,6 +63,7 @@ constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60); constexpr auto kMaxPreviewImages = 3; using ItemPreview = HistoryView::ItemPreview; +using ItemPreviewImage = HistoryView::ItemPreviewImage; [[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call) { auto result = Call(); @@ -191,25 +192,18 @@ using ItemPreview = HistoryView::ItemPreview; return square; } -struct PreparedPreview { - QImage preview; - bool loading = false; - - explicit operator bool() const { - return !preview.isNull() || loading; - } -}; - -[[nodiscard]] PreparedPreview PreparePhotoPreview( +[[nodiscard]] ItemPreviewImage PreparePhotoPreview( not_null item, const std::shared_ptr &media, ImageRoundRadius radius) { + const auto photo = media->owner(); + const auto readyCacheKey = reinterpret_cast(photo.get()); if (const auto small = media->image(PhotoSize::Small)) { - return { PreparePreviewImage(small, radius) }; + return { PreparePreviewImage(small, radius), readyCacheKey }; } else if (const auto thumbnail = media->image(PhotoSize::Thumbnail)) { - return { PreparePreviewImage(thumbnail, radius) }; + return { PreparePreviewImage(thumbnail, radius), readyCacheKey }; } else if (const auto large = media->image(PhotoSize::Large)) { - return { PreparePreviewImage(large, radius) }; + return { PreparePreviewImage(large, radius), readyCacheKey }; } const auto allowedToDownload = [&] { const auto photo = media->owner(); @@ -223,29 +217,32 @@ struct PreparedPreview { item->history()->peer, photo); }(); + const auto cacheKey = allowedToDownload ? 0 : readyCacheKey; if (allowedToDownload) { media->owner()->load(PhotoSize::Small, item->fullId()); } if (const auto blurred = media->thumbnailInline()) { - return { PreparePreviewImage(blurred, radius), allowedToDownload }; + return { PreparePreviewImage(blurred, radius), cacheKey }; } - return { QImage(), allowedToDownload }; + return { QImage(), allowedToDownload ? 0 : cacheKey }; } -[[nodiscard]] PreparedPreview PrepareFilePreviewImage( +[[nodiscard]] ItemPreviewImage PrepareFilePreviewImage( not_null item, const std::shared_ptr &media, ImageRoundRadius radius) { Expects(media->owner()->hasThumbnail()); + const auto document = media->owner(); + const auto readyCacheKey = reinterpret_cast(document.get()); if (const auto thumbnail = media->thumbnail()) { - return { PreparePreviewImage(thumbnail, radius) }; + return { PreparePreviewImage(thumbnail, radius), readyCacheKey }; } - media->owner()->loadThumbnail(item->fullId()); + document->loadThumbnail(item->fullId()); if (const auto blurred = media->thumbnailInline()) { - return { PreparePreviewImage(blurred, radius), true }; + return { PreparePreviewImage(blurred, radius), 0 }; } - return { QImage(), true }; + return { QImage(), 0 }; } [[nodiscard]] QImage PutPlayIcon(QImage preview) { @@ -260,28 +257,17 @@ struct PreparedPreview { return preview; } -[[nodiscard]] PreparedPreview PrepareFilePreview( +[[nodiscard]] ItemPreviewImage PrepareFilePreview( not_null item, const std::shared_ptr &media, ImageRoundRadius radius) { - if (auto result = PrepareFilePreviewImage(item, media, radius)) { - const auto document = media->owner(); - if (!result.preview.isNull() - && (document->isVideoFile() || document->isVideoMessage())) { - result.preview = PutPlayIcon(std::move(result.preview)); - } - return result; + auto result = PrepareFilePreviewImage(item, media, radius); + const auto document = media->owner(); + if (!result.data.isNull() + && (document->isVideoFile() || document->isVideoMessage())) { + result.data = PutPlayIcon(std::move(result.data)); } - Expects(media->owner()->hasThumbnail()); - - if (const auto thumbnail = media->thumbnail()) { - return { PreparePreviewImage(thumbnail, radius) }; - } - media->owner()->loadThumbnail(item->fullId()); - if (const auto blurred = media->thumbnailInline()) { - return { PreparePreviewImage(blurred, radius), true }; - } - return { QImage(), true }; + return result; } [[nodiscard]] bool TryFilePreview(not_null document) { @@ -290,6 +276,20 @@ struct PreparedPreview { && !document->isAudioFile(); } +template +[[nodiscard]] ItemPreviewImage FindCachedPreview( + const std::vector *existing, + not_null data) { + if (!existing) { + return {}; + } + const auto i = ranges::find( + *existing, + reinterpret_cast(data.get()), + &ItemPreviewImage::cacheKey); + return (i != end(*existing)) ? *i : ItemPreviewImage(); +} + } // namespace TextForMimeData WithCaptionClipboardText( @@ -554,22 +554,27 @@ ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const { return toGroupPreview(group->items, options); } } - const auto caption = options.hideCaption - ? QString() - : parent()->originalText().text; - auto images = std::vector(); - const auto media = _photo->createMediaView(); - const auto radius = _chat - ? ImageRoundRadius::Ellipse - : ImageRoundRadius::Small; + auto images = std::vector(); auto context = std::any(); - if (auto prepared = PreparePhotoPreview(parent(), media, radius)) { - images.push_back(std::move(prepared.preview)); - if (prepared.loading) { - context = media; + if (auto cached = FindCachedPreview(options.existing, _photo)) { + images.push_back(std::move(cached)); + } else { + const auto media = _photo->createMediaView(); + const auto radius = _chat + ? ImageRoundRadius::Ellipse + : ImageRoundRadius::Small; + if (auto prepared = PreparePhotoPreview(parent(), media, radius) + ; prepared || !prepared.cacheKey) { + images.push_back(std::move(prepared)); + if (!prepared.cacheKey) { + context = media; + } } } const auto type = tr::lng_in_dlg_photo(tr::now); + const auto caption = options.hideCaption + ? QString() + : parent()->originalText().text; return { .text = WithCaptionDialogsText(type, caption, !images.empty()), .images = std::move(images), @@ -751,6 +756,23 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const { if (const auto sticker = _document->sticker()) { return Media::toPreview(options); } + auto images = std::vector(); + auto context = std::any(); + if (auto cached = FindCachedPreview(options.existing, _document)) { + images.push_back(std::move(cached)); + } else if (TryFilePreview(_document)) { + const auto media = _document->createMediaView(); + const auto radius = _document->isVideoMessage() + ? ImageRoundRadius::Ellipse + : ImageRoundRadius::Small; + if (auto prepared = PrepareFilePreview(parent(), media, radius) + ; prepared || !prepared.cacheKey) { + images.push_back(std::move(prepared)); + if (!prepared.cacheKey) { + context = media; + } + } + } const auto type = [&] { using namespace Ui::Text; if (_document->isVideoMessage()) { @@ -772,22 +794,6 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const { const auto caption = options.hideCaption ? QString() : parent()->originalText().text; - auto images = std::vector(); - const auto media = TryFilePreview(_document) - ? _document->createMediaView() - : nullptr; - const auto radius = _document->isVideoMessage() - ? ImageRoundRadius::Ellipse - : ImageRoundRadius::Small; - auto context = std::any(); - if (media) { - if (auto prepared = PrepareFilePreview(parent(), media, radius)) { - images.push_back(std::move(prepared.preview)); - if (prepared.loading) { - context = media; - } - } - } return { .text = WithCaptionDialogsText(type, caption, !images.empty()), .images = std::move(images), diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index b7ba8b8be..e55bcd88f 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -28,6 +28,7 @@ enum class Context : char; class Element; class Media; struct ItemPreview; +struct ItemPreviewImage; struct ToPreviewOptions; } // namespace HistoryView @@ -75,6 +76,7 @@ public: not_null parent() const; using ToPreviewOptions = HistoryView::ToPreviewOptions; + using ItemPreviewImage = HistoryView::ItemPreviewImage; using ItemPreview = HistoryView::ItemPreview; virtual std::unique_ptr clone(not_null parent) = 0; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 926f8ae0b..e0ae94d6e 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1859,6 +1859,26 @@ void Session::processMessages( processMessages(data.v, type); } +void Session::processExistingMessages( + ChannelData *channel, + const MTPmessages_Messages &data) { + data.match([&](const MTPDmessages_channelMessages &data) { + if (channel) { + channel->ptsReceived(data.vpts().v); + } else { + LOG(("App Error: received messages.channelMessages!")); + } + }, [](const auto &) {}); + + data.match([&](const MTPDmessages_messagesNotModified&) { + LOG(("API Error: received messages.messagesNotModified!")); + }, [&](const auto &data) { + processUsers(data.vusers()); + processChats(data.vchats()); + processMessages(data.vmessages(), NewMessageType::Existing); + }); +} + const Session::Messages *Session::messagesList(ChannelId channelId) const { if (channelId == NoChannel) { return &_messages; diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 630fec10f..9a0d991f6 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -341,6 +341,9 @@ public: void processMessages( const MTPVector &data, NewMessageType type); + void processExistingMessages( + ChannelData *channel, + const MTPmessages_Messages &data); void processMessagesDeleted( ChannelId channelId, const QVector &data); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp index ff0f4d85d..72dd07665 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp @@ -105,6 +105,7 @@ void MessageView::paint( return; } if (_textCachedFor != item.get()) { + options.existing = &_imagesCache; auto preview = item->toPreview(options); if (!preview.images.empty() && preview.imagesInTextPosition > 0) { _senderCache.setText( @@ -140,7 +141,11 @@ void MessageView::paint( ? st::dialogsTextPaletteOver : st::dialogsTextPalette); p.setFont(st::dialogsTextFont); - p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg)); + p.setPen(active + ? st::dialogsTextFgActive + : selected + ? st::dialogsTextFgOver + : st::dialogsTextFg); const auto guard = gsl::finally([&] { p.restoreTextPalette(); }); @@ -161,7 +166,10 @@ void MessageView::paint( if (rect.width() < st::dialogsMiniPreview) { break; } - p.drawImage(rect.x(), rect.y() + st::dialogsMiniPreviewTop, image); + p.drawImage( + rect.x(), + rect.y() + st::dialogsMiniPreviewTop, + image.data); rect.setLeft(rect.x() + st::dialogsMiniPreview + st::dialogsMiniPreviewSkip); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h index ed679f464..54328ec83 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h @@ -18,6 +18,7 @@ namespace Ui { namespace HistoryView { struct ToPreviewOptions; +struct ItemPreviewImage; struct ItemPreview; } // namespace HistoryView @@ -31,6 +32,7 @@ public: ~MessageView(); using ToPreviewOptions = HistoryView::ToPreviewOptions; + using ItemPreviewImage = HistoryView::ItemPreviewImage; using ItemPreview = HistoryView::ItemPreview; void itemInvalidated(not_null item); @@ -50,7 +52,7 @@ private: mutable const HistoryItem *_textCachedFor = nullptr; mutable Ui::Text::String _senderCache; mutable Ui::Text::String _textCache; - mutable std::vector _imagesCache; + mutable std::vector _imagesCache; mutable std::unique_ptr _loadingContext; }; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index f1233c5c1..b4beaa22a 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1253,27 +1253,31 @@ void History::addOlderSlice(const QVector &slice) { } if (const auto added = createItems(slice); !added.empty()) { - startBuildingFrontBlock(added.size()); - for (const auto &item : added) { - addItemToBlock(item); - } - finishBuildingFrontBlock(); - - if (loadedAtBottom()) { - // Add photos to overview and authors to lastAuthors. - addItemsToLists(added); - } - addToSharedMedia(added); + addCreatedOlderSlice(added); } else { // If no items were added it means we've loaded everything old. _loadedAtTop = true; addEdgesToSharedMedia(); } - checkLocalMessages(); checkLastMessage(); } +void History::addCreatedOlderSlice( + const std::vector> &items) { + startBuildingFrontBlock(items.size()); + for (const auto &item : items) { + addItemToBlock(item); + } + finishBuildingFrontBlock(); + + if (loadedAtBottom()) { + // Add photos to overview and authors to lastAuthors. + addItemsToLists(items); + } + addToSharedMedia(items); +} + void History::addNewerSlice(const QVector &slice) { bool wasLoadedAtBottom = loadedAtBottom(); @@ -2266,6 +2270,14 @@ void History::setChatListMessage(HistoryItem *item) { } _chatListMessage = item; setChatListTimeId(item->date()); + + // If we have a single message from a group, request the full album. + if (hasOrphanMediaGroupPart() + && !item->toPreview({ + .hideSender = true, + .hideCaption = true }).images.empty()) { + owner().histories().requestGroupAround(item); + } } else if (!_chatListMessage || *_chatListMessage) { _chatListMessage = nullptr; updateChatListEntry(); @@ -2422,6 +2434,44 @@ void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) { setChatListMessage(item); } +void History::applyChatListGroup( + ChannelId channelId, + const MTPmessages_Messages &data) { + if (!isEmpty() + || !_chatListMessage + || !*_chatListMessage + || (*_chatListMessage)->history()->channelId() != channelId + || (*_chatListMessage)->history() != this + || !_lastMessage + || !*_lastMessage) { + return; + } + // Apply loaded album as a last slice. + const auto processMessages = [&](const MTPVector &messages) { + auto items = std::vector>(); + items.reserve(messages.v.size()); + for (const auto &message : messages.v) { + const auto id = IdFromMessage(message); + if (const auto message = owner().message(channelId, id)) { + items.push_back(message); + } + } + if (!ranges::contains(items, not_null(*_lastMessage)) + || !ranges::contains(items, not_null(*_chatListMessage))) { + return; + } + _loadedAtBottom = true; + ranges::sort(items, ranges::less{}, &HistoryItem::id); + addCreatedOlderSlice(items); + checkLocalMessages(); + checkLastMessage(); + }; + data.match([&](const MTPDmessages_messagesNotModified &) { + }, [&](const auto &data) { + processMessages(data.vmessages()); + }); +} + HistoryItem *History::lastMessage() const { return _lastMessage.value_or(nullptr); } diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index e857c57ee..956be8a95 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -409,6 +409,10 @@ public: void setFakeChatListMessageFrom(const MTPmessages_Messages &data); void checkChatListMessageRemoved(not_null item); + void applyChatListGroup( + ChannelId channelId, + const MTPmessages_Messages &data); + void forgetScrollState() { scrollTopItem = nullptr; } @@ -516,6 +520,9 @@ private: return _buildingFrontBlock != nullptr; } + void addCreatedOlderSlice( + const std::vector> &items); + void checkForLoadedAtTop(not_null added); void mainViewRemoved( not_null block, diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 456eaae33..e00ba3791 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -57,20 +57,30 @@ enum class PointState : char; enum class Context : char; class ElementDelegate; -struct ToPreviewOptions { - bool hideSender = false; - bool hideCaption = false; - bool generateImages = true; - bool ignoreGroup = false; +struct ItemPreviewImage { + QImage data; + uint64 cacheKey = 0; + + explicit operator bool() const { + return !data.isNull(); + } }; struct ItemPreview { QString text; - std::vector images; + std::vector images; int imagesInTextPosition = 0; std::any loadingContext; }; +struct ToPreviewOptions { + const std::vector *existing = nullptr; + bool hideSender = false; + bool hideCaption = false; + bool generateImages = true; + bool ignoreGroup = false; +}; + } // namespace HistoryView struct HiddenSenderInfo; diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index d58c46df1..bfa2f5e69 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -804,7 +804,7 @@ void Notification::updateNotifyDisplay() { p.setTextPalette(st::dialogsTextPalette); p.setPen(st::dialogsTextFg); p.setFont(st::dialogsTextFont); - const auto text = _item // #TODO minis use images + const auto text = _item ? _item->toPreview({ .hideSender = reminder, .generateImages = false,