From 4dee21c0e6a83ee4f86921494bd49f56ae4035da Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 15 Feb 2022 05:20:55 +0300 Subject: [PATCH] Added userpics support to sponsored messages. --- Telegram/SourceFiles/data/data_cloud_file.cpp | 2 +- Telegram/SourceFiles/data/data_cloud_file.h | 2 +- .../data/data_sponsored_messages.cpp | 19 +++++++++++- .../data/data_sponsored_messages.h | 2 ++ .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 2 +- .../history/history_inner_widget.cpp | 29 +++++++++++++++---- .../history/history_inner_widget.h | 3 ++ .../history/history_item_components.cpp | 22 +++++++++++++- .../history/history_item_components.h | 11 ++++++- .../SourceFiles/history/history_message.cpp | 5 ++++ .../history/view/history_view_element.cpp | 3 +- .../history/view/history_view_list_widget.cpp | 29 +++++++++++++++---- .../history/view/history_view_list_widget.h | 3 ++ .../history/view/history_view_message.cpp | 6 ++-- 14 files changed, 117 insertions(+), 21 deletions(-) diff --git a/Telegram/SourceFiles/data/data_cloud_file.cpp b/Telegram/SourceFiles/data/data_cloud_file.cpp index d60cce7ba..d99ad6ea3 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.cpp +++ b/Telegram/SourceFiles/data/data_cloud_file.cpp @@ -146,7 +146,7 @@ std::shared_ptr CloudImage::createView() { return view; } -std::shared_ptr CloudImage::activeView() { +std::shared_ptr CloudImage::activeView() const { return _view.lock(); } diff --git a/Telegram/SourceFiles/data/data_cloud_file.h b/Telegram/SourceFiles/data/data_cloud_file.h index fe1047d2a..799a1a688 100644 --- a/Telegram/SourceFiles/data/data_cloud_file.h +++ b/Telegram/SourceFiles/data/data_cloud_file.h @@ -80,7 +80,7 @@ public: [[nodiscard]] int byteSize() const; [[nodiscard]] std::shared_ptr createView(); - [[nodiscard]] std::shared_ptr activeView(); + [[nodiscard]] std::shared_ptr activeView() const; [[nodiscard]] bool isCurrentView( const std::shared_ptr &view) const; diff --git a/Telegram/SourceFiles/data/data_sponsored_messages.cpp b/Telegram/SourceFiles/data/data_sponsored_messages.cpp index 66adb4d0f..8399febad 100644 --- a/Telegram/SourceFiles/data/data_sponsored_messages.cpp +++ b/Telegram/SourceFiles/data/data_sponsored_messages.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "history/history.h" #include "main/main_session.h" +#include "ui/image/image_location_factory.h" namespace Data { namespace { @@ -164,6 +165,7 @@ void SponsoredMessages::append( .isPublic = (channel && channel->isPublic()), .isBot = (peer->isUser() && peer->asUser()->isBot()), .isExactPost = exactPost, + .userpic = { .location = peer->userpicLocation() }, }; }; const auto from = [&]() -> SponsoredFrom { @@ -173,13 +175,28 @@ void SponsoredMessages::append( (data.vchannel_post() != nullptr)); } Assert(data.vchat_invite()); - return data.vchat_invite()->match([](const MTPDchatInvite &data) { + return data.vchat_invite()->match([&](const MTPDchatInvite &data) { + auto userpic = data.vphoto().match([&](const MTPDphoto &data) { + for (const auto &size : data.vsizes().v) { + const auto result = Images::FromPhotoSize( + _session, + data, + size); + if (result.location.valid()) { + return result; + } + } + return ImageWithLocation{}; + }, [](const MTPDphotoEmpty &) { + return ImageWithLocation{}; + }); return SponsoredFrom{ .title = qs(data.vtitle()), .isBroadcast = data.is_broadcast(), .isMegagroup = data.is_megagroup(), .isChannel = data.is_channel(), .isPublic = data.is_public(), + .userpic = std::move(userpic), }; }, [&](const MTPDchatInviteAlready &data) { const auto chat = _session->data().processChat(data.vchat()); diff --git a/Telegram/SourceFiles/data/data_sponsored_messages.h b/Telegram/SourceFiles/data/data_sponsored_messages.h index eaa980661..6159e4086 100644 --- a/Telegram/SourceFiles/data/data_sponsored_messages.h +++ b/Telegram/SourceFiles/data/data_sponsored_messages.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "base/timer.h" +#include "ui/image/image_location.h" class History; @@ -29,6 +30,7 @@ struct SponsoredFrom { bool isPublic = false; bool isBot = false; bool isExactPost = false; + ImageWithLocation userpic; }; struct SponsoredMessage { diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index d4078abbd..1e516b554 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -365,7 +365,7 @@ void paintRow( active, fullWidth); } else if (hiddenSenderInfo) { - hiddenSenderInfo->userpic.paint( + hiddenSenderInfo->emptyUserpic.paint( p, st::dialogsPadding.x(), st::dialogsPadding.y(), diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 1a7f98a5c..75f9c3834 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1075,12 +1075,29 @@ void HistoryInner::paintEvent(QPaintEvent *e) { width(), st::msgPhotoSize); } else if (const auto info = view->data()->hiddenSenderInfo()) { - info->userpic.paint( - p, - st::historyPhotoLeft, - userpicTop, - width(), - st::msgPhotoSize); + if (info->customUserpic.empty()) { + info->emptyUserpic.paint( + p, + st::historyPhotoLeft, + userpicTop, + width(), + st::msgPhotoSize); + } else { + const auto painted = info->paintCustomUserpic( + p, + st::historyPhotoLeft, + userpicTop, + width(), + st::msgPhotoSize); + if (!painted) { + const auto itemId = view->data()->fullId(); + auto &v = _sponsoredUserpics[itemId.msg]; + if (!info->customUserpic.isCurrentView(v)) { + v = info->customUserpic.createView(); + info->customUserpic.load(&session(), itemId); + } + } + } } else { Unexpected("Corrupt forwarded information in message."); } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 237a73b02..0ed6d9bce 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -428,6 +428,9 @@ private: base::flat_map< not_null, std::shared_ptr> _userpics, _userpicsCache; + base::flat_map< + MsgId, + std::shared_ptr> _sponsoredUserpics; std::unique_ptr _reactionsManager; diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index eb7065920..67d8db9d6 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -89,7 +89,7 @@ void HistoryMessageVia::resize(int32 availw) const { HiddenSenderInfo::HiddenSenderInfo(const QString &name, bool external) : name(name) , colorPeerId(Data::FakePeerIdForJustName(name)) -, userpic( +, emptyUserpic( Data::PeerUserpicColor(colorPeerId), (external ? Ui::EmptyUserpic::ExternalName() @@ -107,6 +107,26 @@ HiddenSenderInfo::HiddenSenderInfo(const QString &name, bool external) } } +bool HiddenSenderInfo::paintCustomUserpic( + Painter &p, + int x, + int y, + int outerWidth, + int size) const { + const auto view = customUserpic.activeView(); + if (const auto image = view ? view->image() : nullptr) { + const auto circled = Images::Option::RoundCircle; + p.drawPixmap( + x, + y, + image->pix(size, size, { .options = circled })); + return true; + } else { + emptyUserpic.paint(p, x, y, outerWidth, size); + return false; + } +} + void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { auto phrase = TextWithEntities(); const auto fromChannel = originalSender diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 7a84be750..95a350d2e 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/data_cloud_file.h" #include "history/history_item.h" #include "ui/empty_userpic.h" #include "ui/effects/animations.h" @@ -75,8 +76,16 @@ struct HiddenSenderInfo { QString firstName; QString lastName; PeerId colorPeerId = 0; - Ui::EmptyUserpic userpic; Ui::Text::String nameText; + Ui::EmptyUserpic emptyUserpic; + mutable Data::CloudImage customUserpic; + + [[nodiscard]] bool paintCustomUserpic( + Painter &p, + int x, + int y, + int outerWidth, + int size) const; inline bool operator==(const HiddenSenderInfo &other) const { return name == other.name; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index f741da5e6..1e044f944 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -1988,6 +1988,11 @@ void HistoryMessage::setSponsoredFrom(const Data::SponsoredFrom &from) { sponsored->sender = std::make_unique( from.title, false); + if (from.userpic.location.valid()) { + sponsored->sender->customUserpic.set( + &history()->session(), + from.userpic); + } using Type = HistoryMessageSponsored::Type; sponsored->type = from.isExactPost diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 0fca73a21..ea82ed344 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -636,7 +636,8 @@ ClickHandlerPtr Element::fromLink() const { const auto my = context.other.value(); if (const auto window = ContextOrSessionWindow(my, session)) { auto &sponsored = session->data().sponsoredMessages(); - const auto details = sponsored.lookupDetails(my.itemId); + const auto itemId = my.itemId ? my.itemId : item->fullId(); + const auto details = sponsored.lookupDetails(itemId); if (const auto &hash = details.hash) { Api::CheckChatInvite(window, *hash); } else if (const auto peer = details.peer) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 1a122b8d0..5e26161d4 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -1812,12 +1812,29 @@ void ListWidget::paintEvent(QPaintEvent *e) { view->width(), st::msgPhotoSize); } else if (const auto info = view->data()->hiddenSenderInfo()) { - info->userpic.paint( - p, - st::historyPhotoLeft, - userpicTop, - view->width(), - st::msgPhotoSize); + if (info->customUserpic.empty()) { + info->emptyUserpic.paint( + p, + st::historyPhotoLeft, + userpicTop, + view->width(), + st::msgPhotoSize); + } else { + const auto painted = info->paintCustomUserpic( + p, + st::historyPhotoLeft, + userpicTop, + view->width(), + st::msgPhotoSize); + if (!painted) { + const auto itemId = view->data()->fullId(); + auto &v = _sponsoredUserpics[itemId.msg]; + if (!info->customUserpic.isCurrentView(v)) { + v = info->customUserpic.createView(); + info->customUserpic.load(&session(), itemId); + } + } + } } else { Unexpected("Corrupt forwarded information in message."); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index e917c5b77..2ed870cf4 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -564,6 +564,9 @@ private: base::flat_map< not_null, std::shared_ptr> _userpics, _userpicsCache; + base::flat_map< + MsgId, + std::shared_ptr> _sponsoredUserpics; const std::unique_ptr _pathGradient; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index a703edcd8..19a6071a1 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1390,8 +1390,10 @@ bool Message::hasFromPhoto() const { case Context::Pinned: case Context::Replies: { const auto item = message(); - if (item->isPost() - || item->isEmpty() + if (item->isPost()) { + return item->isSponsored(); + } + if (item->isEmpty() || (context() == Context::Replies && item->isDiscussionPost())) { return false; } else if (delegate()->elementIsChatWide()) {