From 37fb94cbfb28e31ab2465846d64e67f8733f1f7f Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 12 Oct 2020 16:24:45 +0300 Subject: [PATCH] Load and show image previews in pinned bar. --- Telegram/SourceFiles/data/data_document.cpp | 9 ++ Telegram/SourceFiles/data/data_document.h | 1 + .../SourceFiles/data/data_media_types.cpp | 37 ++++++++ Telegram/SourceFiles/data/data_media_types.h | 6 ++ Telegram/SourceFiles/data/data_photo.cpp | 7 ++ Telegram/SourceFiles/data/data_photo.h | 1 + .../SourceFiles/data/data_reply_preview.cpp | 4 + .../SourceFiles/data/data_reply_preview.h | 1 + .../history/view/history_view_pinned_bar.cpp | 85 +++++++++++++++---- 9 files changed, 136 insertions(+), 15 deletions(-) diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 56aee3cd0..38a511a8e 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -1266,6 +1266,15 @@ Image *DocumentData::getReplyPreview(Data::FileOrigin origin) { return _replyPreview->image(origin); } +bool DocumentData::replyPreviewLoaded() const { + if (!hasThumbnail()) { + return true; + } else if (!_replyPreview) { + return false; + } + return _replyPreview->loaded(); +} + StickerData *DocumentData::sticker() const { return (type == StickerDocument) ? static_cast(_additional.get()) diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 4c065e476..e8b5b905f 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -126,6 +126,7 @@ public: [[nodiscard]] bool saveToCache() const; [[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin); + [[nodiscard]] bool replyPreviewLoaded() const; [[nodiscard]] StickerData *sticker() const; [[nodiscard]] Data::FileOrigin stickerSetOrigin() const; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 40309e4c5..c87b7b733 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -209,6 +209,10 @@ Image *Media::replyPreview() const { return nullptr; } +bool Media::replyPreviewLoaded() const { + return true; +} + bool Media::allowsForward() const { return true; } @@ -312,6 +316,10 @@ Image *MediaPhoto::replyPreview() const { return _photo->getReplyPreview(parent()->fullId()); } +bool MediaPhoto::replyPreviewLoaded() const { + return _photo->replyPreviewLoaded(); +} + QString MediaPhoto::notificationText() const { return WithCaptionNotificationText( tr::lng_in_dlg_photo(tr::now), @@ -476,6 +484,10 @@ Image *MediaFile::replyPreview() const { return _document->getReplyPreview(parent()->fullId()); } +bool MediaFile::replyPreviewLoaded() const { + return _document->replyPreviewLoaded(); +} + QString MediaFile::chatListText() const { if (const auto sticker = _document->sticker()) { return Media::chatListText(); @@ -987,6 +999,15 @@ Image *MediaWebPage::replyPreview() const { return nullptr; } +bool MediaWebPage::replyPreviewLoaded() const { + if (const auto document = MediaWebPage::document()) { + return document->replyPreviewLoaded(); + } else if (const auto photo = MediaWebPage::photo()) { + return photo->replyPreviewLoaded(); + } + return true; +} + QString MediaWebPage::chatListText() const { return notificationText(); } @@ -1051,6 +1072,15 @@ Image *MediaGame::replyPreview() const { return nullptr; } +bool MediaGame::replyPreviewLoaded() const { + if (const auto document = _game->document) { + return document->replyPreviewLoaded(); + } else if (const auto photo = _game->photo) { + return photo->replyPreviewLoaded(); + } + return true; +} + QString MediaGame::notificationText() const { // Add a game controller emoji before game title. auto result = QString(); @@ -1153,6 +1183,13 @@ Image *MediaInvoice::replyPreview() const { return nullptr; } +bool MediaInvoice::replyPreviewLoaded() const { + if (const auto photo = _invoice.photo) { + return photo->replyPreviewLoaded(); + } + return true; +} + QString MediaInvoice::notificationText() const { return _invoice.title; } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index caba0e25c..5037a2592 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -88,6 +88,7 @@ public: virtual bool canBeGrouped() const; virtual bool hasReplyPreview() const; virtual Image *replyPreview() const; + virtual bool replyPreviewLoaded() const; // Returns text with link-start and link-end commands for service-color highlighting. // Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text" virtual QString chatListText() const; @@ -143,6 +144,7 @@ public: bool canBeGrouped() const override; bool hasReplyPreview() const override; Image *replyPreview() const override; + bool replyPreviewLoaded() const override; QString chatListText() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; @@ -180,6 +182,7 @@ public: bool canBeGrouped() const override; bool hasReplyPreview() const override; Image *replyPreview() const override; + bool replyPreviewLoaded() const override; QString chatListText() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; @@ -311,6 +314,7 @@ public: bool hasReplyPreview() const override; Image *replyPreview() const override; + bool replyPreviewLoaded() const override; QString chatListText() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; @@ -341,6 +345,7 @@ public: bool hasReplyPreview() const override; Image *replyPreview() const override; + bool replyPreviewLoaded() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; TextForMimeData clipboardText() const override; @@ -377,6 +382,7 @@ public: bool hasReplyPreview() const override; Image *replyPreview() const override; + bool replyPreviewLoaded() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; TextForMimeData clipboardText() const override; diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index d5ede173c..b1d67d1cd 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -205,6 +205,13 @@ Image *PhotoData::getReplyPreview(Data::FileOrigin origin) { return _replyPreview->image(origin); } +bool PhotoData::replyPreviewLoaded() const { + if (!_replyPreview) { + return false; + } + return _replyPreview->loaded(); +} + void PhotoData::setRemoteLocation( int32 dc, uint64 access, diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index 09263dcf9..bcd3f9ccf 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -65,6 +65,7 @@ public: [[nodiscard]] bool waitingForAlbum() const; [[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin); + [[nodiscard]] bool replyPreviewLoaded() const; void setRemoteLocation( int32 dc, diff --git a/Telegram/SourceFiles/data/data_reply_preview.cpp b/Telegram/SourceFiles/data/data_reply_preview.cpp index 960328506..1067e2346 100644 --- a/Telegram/SourceFiles/data/data_reply_preview.cpp +++ b/Telegram/SourceFiles/data/data_reply_preview.cpp @@ -107,4 +107,8 @@ Image *ReplyPreview::image(Data::FileOrigin origin) { return _image.get(); } +bool ReplyPreview::loaded() const { + return _checked; +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_reply_preview.h b/Telegram/SourceFiles/data/data_reply_preview.h index 3c31cbe84..01314e7ef 100644 --- a/Telegram/SourceFiles/data/data_reply_preview.h +++ b/Telegram/SourceFiles/data/data_reply_preview.h @@ -24,6 +24,7 @@ public: ~ReplyPreview(); [[nodiscard]] Image *image(Data::FileOrigin origin); + [[nodiscard]] bool loaded() const; private: void prepare(not_null image, Images::Options options); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp index 824705a77..4401bbb09 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp @@ -23,29 +23,84 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { +[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview( + not_null item, + PinnedIdType type) { + const auto media = item->media(); + const auto poll = media ? media->poll() : nullptr; + return Ui::MessageBarContent{ + .id = item->id, + .title = ((type == PinnedIdType::First) + ? tr::lng_pinned_previous(tr::now) // #TODO pinned first? + : (type == PinnedIdType::Middle) + ? tr::lng_pinned_previous(tr::now) + : !poll + ? tr::lng_pinned_message(tr::now) + : poll->quiz() + ? tr::lng_pinned_quiz(tr::now) + : tr::lng_pinned_poll(tr::now)), + .text = item->inReplyText(), + }; +} + +[[nodiscard]] Ui::MessageBarContent ContentWithPreview( + not_null item, + PinnedIdType type, + Image *preview) { + auto result = ContentWithoutPreview(item, type); + if (!preview) { + static const auto kEmpty = [&] { + const auto size = st::historyReplyHeight * cIntRetinaFactor(); + auto result = QImage( + QSize(size, size), + QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + result.setDevicePixelRatio(cRetinaFactor()); + return result; + }(); + result.preview = kEmpty; + } else { + result.preview = preview->original(); + } + return result; +} + [[nodiscard]] rpl::producer ContentByItem( not_null item, PinnedIdType type) { return item->history()->session().changes().messageFlagsValue( item, Data::MessageUpdate::Flag::Edited - ) | rpl::map([=] { + ) | rpl::map([=]() -> rpl::producer { const auto media = item->media(); - const auto poll = media ? media->poll() : nullptr; - return Ui::MessageBarContent{ - .id = item->id, - .title = ((type == PinnedIdType::First) - ? tr::lng_pinned_previous(tr::now) // #TODO pinned first? - : (type == PinnedIdType::Middle) - ? tr::lng_pinned_previous(tr::now) - : !poll - ? tr::lng_pinned_message(tr::now) - : poll->quiz() - ? tr::lng_pinned_quiz(tr::now) - : tr::lng_pinned_poll(tr::now)), - .text = item->inReplyText(), + if (!media || !media->hasReplyPreview()) { + return rpl::single(ContentWithoutPreview(item, type)); + } + constexpr auto kFullLoaded = 2; + constexpr auto kSomeLoaded = 1; + constexpr auto kNotLoaded = 0; + const auto loadedLevel = [=] { + const auto preview = media->replyPreview(); + return media->replyPreviewLoaded() + ? kFullLoaded + : preview + ? kSomeLoaded + : kNotLoaded; }; - }); + return rpl::single( + loadedLevel() + ) | rpl::then( + item->history()->session().downloaderTaskFinished( + ) | rpl::map(loadedLevel) + ) | rpl::distinct_until_changed( + ) | rpl::take_while([=](int loadLevel) { + return loadLevel < kFullLoaded; + }) | rpl::then( + rpl::single(kFullLoaded) + ) | rpl::map([=] { + return ContentWithPreview(item, type, media->replyPreview()); + }); + }) | rpl::flatten_latest(); } [[nodiscard]] rpl::producer ContentByItemId(