Replaced style of sponsored messages with fake webpage.

This commit is contained in:
23rd 2023-11-15 18:18:18 +03:00 committed by John Preston
parent 17f89ba1f9
commit 4c5c2aadc4
10 changed files with 168 additions and 88 deletions

View file

@ -1823,8 +1823,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_forwarded_hidden" = "The account was hidden by the user."; "lng_forwarded_hidden" = "The account was hidden by the user.";
"lng_forwarded_imported" = "This message was imported from another app. It may not be real."; "lng_forwarded_imported" = "This message was imported from another app. It may not be real.";
"lng_signed_author" = "Author: {user}"; "lng_signed_author" = "Author: {user}";
"lng_sponsored" = "sponsored"; "lng_sponsored_message_title" = "Sponsored";
"lng_recommended" = "recommended"; "lng_recommended_message_title" = "Recommended";
"lng_edited" = "edited"; "lng_edited" = "edited";
"lng_edited_date" = "Edited: {date}"; "lng_edited_date" = "Edited: {date}";
"lng_sent_date" = "Sent: {date}"; "lng_sent_date" = "Sent: {date}";

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h" #include "base/unixtime.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_peer_id.h" #include "data/data_peer_id.h"
#include "data/data_photo.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "history/history.h" #include "history/history.h"
@ -275,39 +276,22 @@ void SponsoredMessages::append(
.isBot = (peer->isUser() && peer->asUser()->isBot()), .isBot = (peer->isUser() && peer->asUser()->isBot()),
.isExactPost = exactPost, .isExactPost = exactPost,
.isRecommended = data.is_recommended(), .isRecommended = data.is_recommended(),
.userpic = { .location = peer->userpicLocation() },
.isForceUserpicDisplay = data.is_show_peer_photo(), .isForceUserpicDisplay = data.is_show_peer_photo(),
}; };
}; };
const auto externalLink = data.vwebpage() const auto externalLink = data.vwebpage()
? qs(data.vwebpage()->data().vurl()) ? qs(data.vwebpage()->data().vurl())
: QString(); : QString();
const auto userpicFromPhoto = [&](const MTPphoto &photo) {
return photo.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{};
});
};
const auto from = [&]() -> SponsoredFrom { const auto from = [&]() -> SponsoredFrom {
if (const auto webpage = data.vwebpage()) { if (const auto webpage = data.vwebpage()) {
const auto &data = webpage->data(); const auto &data = webpage->data();
auto userpic = data.vphoto() const auto photoId = data.vphoto()
? userpicFromPhoto(*data.vphoto()) ? _session->data().processPhoto(*data.vphoto())->id
: ImageWithLocation{}; : PhotoId(0);
return SponsoredFrom{ return SponsoredFrom{
.title = qs(data.vsite_name()), .title = qs(data.vsite_name()),
.externalLink = externalLink, .externalLink = externalLink,
.userpic = std::move(userpic), .externalLinkPhotoId = photoId,
.isForceUserpicDisplay = message.data().is_show_peer_photo(), .isForceUserpicDisplay = message.data().is_show_peer_photo(),
}; };
} else if (const auto fromId = data.vfrom_id()) { } else if (const auto fromId = data.vfrom_id()) {
@ -317,14 +301,12 @@ void SponsoredMessages::append(
} }
Assert(data.vchat_invite()); Assert(data.vchat_invite());
return data.vchat_invite()->match([&](const MTPDchatInvite &data) { return data.vchat_invite()->match([&](const MTPDchatInvite &data) {
auto userpic = userpicFromPhoto(data.vphoto());
return SponsoredFrom{ return SponsoredFrom{
.title = qs(data.vtitle()), .title = qs(data.vtitle()),
.isBroadcast = data.is_broadcast(), .isBroadcast = data.is_broadcast(),
.isMegagroup = data.is_megagroup(), .isMegagroup = data.is_megagroup(),
.isChannel = data.is_channel(), .isChannel = data.is_channel(),
.isPublic = data.is_public(), .isPublic = data.is_public(),
.userpic = std::move(userpic),
.isForceUserpicDisplay = message.data().is_show_peer_photo(), .isForceUserpicDisplay = message.data().is_show_peer_photo(),
}; };
}, [&](const MTPDchatInviteAlready &data) { }, [&](const MTPDchatInviteAlready &data) {
@ -437,7 +419,7 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
const auto &hash = data.chatInviteHash; const auto &hash = data.chatInviteHash;
using InfoList = std::vector<TextWithEntities>; using InfoList = std::vector<TextWithEntities>;
const auto info = (!data.sponsorInfo.text.isEmpty() auto info = (!data.sponsorInfo.text.isEmpty()
&& !data.additionalInfo.text.isEmpty()) && !data.additionalInfo.text.isEmpty())
? InfoList{ data.sponsorInfo, data.additionalInfo } ? InfoList{ data.sponsorInfo, data.additionalInfo }
: !data.sponsorInfo.text.isEmpty() : !data.sponsorInfo.text.isEmpty()
@ -451,6 +433,12 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
.msgId = data.msgId, .msgId = data.msgId,
.info = std::move(info), .info = std::move(info),
.externalLink = data.externalLink, .externalLink = data.externalLink,
.isForceUserpicDisplay = data.from.isForceUserpicDisplay,
.buttonText = !data.externalLink.isEmpty()
? tr::lng_view_button_external_link(tr::now)
: data.from.isBot
? tr::lng_view_button_bot(tr::now)
: QString(),
}; };
} }

View file

@ -32,7 +32,7 @@ struct SponsoredFrom {
bool isExactPost = false; bool isExactPost = false;
bool isRecommended = false; bool isRecommended = false;
QString externalLink; QString externalLink;
ImageWithLocation userpic; PhotoId externalLinkPhotoId;
bool isForceUserpicDisplay = false; bool isForceUserpicDisplay = false;
}; };
@ -61,6 +61,8 @@ public:
MsgId msgId; MsgId msgId;
std::vector<TextWithEntities> info; std::vector<TextWithEntities> info;
QString externalLink; QString externalLink;
bool isForceUserpicDisplay = false;
QString buttonText;
}; };
using RandomId = QByteArray; using RandomId = QByteArray;
explicit SponsoredMessages(not_null<Session*> owner); explicit SponsoredMessages(not_null<Session*> owner);

View file

@ -320,6 +320,7 @@ enum class MediaWebPageFlag : uint8 {
ForceSmallMedia = (1 << 1), ForceSmallMedia = (1 << 1),
Manual = (1 << 2), Manual = (1 << 2),
Safe = (1 << 3), Safe = (1 << 3),
Sponsored = (1 << 4),
}; };
inline constexpr bool is_flag_type(MediaWebPageFlag) { return true; } inline constexpr bool is_flag_type(MediaWebPageFlag) { return true; }
using MediaWebPageFlags = base::flags<MediaWebPageFlag>; using MediaWebPageFlags = base::flags<MediaWebPageFlag>;

View file

@ -695,13 +695,42 @@ HistoryItem::HistoryItem(
? injectedAfter->date() ? injectedAfter->date()
: 0), : 0),
/*from.peer ? from.peer->id : */PeerId(0)) { /*from.peer ? from.peer->id : */PeerId(0)) {
createComponentsHelper( _flags |= MessageFlag::Sponsored;
_flags,
FullReplyTo(), const auto webPageType = from.isExactPost
UserId(0), // viaBotId ? WebPageType::Message
QString(), // postAuthor : from.isBot
HistoryMessageMarkupData()); ? WebPageType::Bot
setText(textWithEntities); : from.isBroadcast
? WebPageType::Channel
: (from.peer && from.peer->isUser())
? WebPageType::User
: WebPageType::Group;
const auto webpage = history->peer->owner().webpage(
history->peer->owner().nextLocalMessageId().bare,
webPageType,
from.externalLink,
from.externalLink,
from.isRecommended
? tr::lng_recommended_message_title(tr::now)
: tr::lng_sponsored_message_title(tr::now),
from.title,
textWithEntities,
from.externalLinkPhotoId
? history->owner().photo(from.externalLinkPhotoId)
: nullptr,
nullptr,
WebPageCollage(),
0,
QString(),
false,
0);
auto webpageMedia = std::make_unique<Data::MediaWebPage>(
this,
webpage,
MediaWebPageFlag::Sponsored);
_media = std::move(webpageMedia);
setSponsoredFrom(from); setSponsoredFrom(from);
} }

View file

@ -445,11 +445,14 @@ QSize BottomInfo::countCurrentSize(int newWidth) {
if (newWidth >= maxWidth()) { if (newWidth >= maxWidth()) {
return optimalSize(); return optimalSize();
} }
const auto dateHeight = (_data.flags & Data::Flag::Sponsored)
? 0
: st::msgDateFont->height;
const auto noReactionsWidth = maxWidth() - _reactionsMaxWidth; const auto noReactionsWidth = maxWidth() - _reactionsMaxWidth;
accumulate_min(newWidth, std::max(noReactionsWidth, _reactionsMaxWidth)); accumulate_min(newWidth, std::max(noReactionsWidth, _reactionsMaxWidth));
return QSize( return QSize(
newWidth, newWidth,
st::msgDateFont->height + countReactionsHeight(newWidth)); dateHeight + countReactionsHeight(newWidth));
} }
void BottomInfo::layout() { void BottomInfo::layout() {
@ -478,10 +481,8 @@ void BottomInfo::layoutDateText() {
const auto name = _authorElided const auto name = _authorElided
? st::msgDateFont->elided(author, maxWidth - afterAuthorWidth) ? st::msgDateFont->elided(author, maxWidth - afterAuthorWidth)
: author; : author;
const auto full = (_data.flags & Data::Flag::Recommended) const auto full = (_data.flags & Data::Flag::Sponsored)
? tr::lng_recommended(tr::now) ? QString()
: (_data.flags & Data::Flag::Sponsored)
? tr::lng_sponsored(tr::now)
: (_data.flags & Data::Flag::Imported) : (_data.flags & Data::Flag::Imported)
? (date + ' ' + tr::lng_imported(tr::now)) ? (date + ' ' + tr::lng_imported(tr::now))
: name.isEmpty() : name.isEmpty()
@ -568,7 +569,10 @@ QSize BottomInfo::countOptimalSize() {
} }
_reactionsMaxWidth = countReactionsMaxWidth(); _reactionsMaxWidth = countReactionsMaxWidth();
width += _reactionsMaxWidth; width += _reactionsMaxWidth;
return QSize(width, st::msgDateFont->height); const auto dateHeight = (_data.flags & Data::Flag::Sponsored)
? 0
: st::msgDateFont->height;
return QSize(width, dateHeight);
} }
BottomInfo::Reaction BottomInfo::prepareReactionWithId( BottomInfo::Reaction BottomInfo::prepareReactionWithId(
@ -644,10 +648,7 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
if (message->context() == Context::Replies) { if (message->context() == Context::Replies) {
result.flags |= Flag::RepliesContext; result.flags |= Flag::RepliesContext;
} }
if (const auto sponsored = item->Get<HistoryMessageSponsored>()) { if (item->isSponsored()) {
if (sponsored->recommended) {
result.flags |= Flag::Recommended;
}
result.flags |= Flag::Sponsored; result.flags |= Flag::Sponsored;
} }
if (item->isPinned() && message->context() != Context::Pinned) { if (item->isPinned() && message->context() != Context::Pinned) {

View file

@ -44,7 +44,6 @@ public:
Sponsored = 0x10, Sponsored = 0x10,
Pinned = 0x20, Pinned = 0x20,
Imported = 0x40, Imported = 0x40,
Recommended = 0x80,
//Unread, // We don't want to pass and update it in Date for now. //Unread, // We don't want to pass and update it in Date for now.
}; };
friend inline constexpr bool is_flag_type(Flag) { return true; }; friend inline constexpr bool is_flag_type(Flag) { return true; };

View file

@ -1996,14 +1996,6 @@ bool Message::hasFromPhoto() const {
case Context::Replies: { case Context::Replies: {
const auto item = data(); const auto item = data();
if (item->isPost()) { if (item->isPost()) {
if (item->isSponsored()) {
if (item->history()->peer->isMegagroup()) {
return true;
}
if (const auto info = item->Get<HistoryMessageSponsored>()) {
return info->isForceUserpicDisplay;
}
}
return false; return false;
} }
if (item->isEmpty() if (item->isEmpty()
@ -3098,10 +3090,8 @@ int Message::viewButtonHeight() const {
void Message::updateViewButtonExistence() { void Message::updateViewButtonExistence() {
const auto item = data(); const auto item = data();
const auto sponsored = item->Get<HistoryMessageSponsored>(); const auto media = item->media();
const auto media = sponsored ? nullptr : item->media(); const auto has = (media && ViewButton::MediaHasViewButton(media));
const auto has = sponsored
|| (media && ViewButton::MediaHasViewButton(media));
if (!has) { if (!has) {
_viewButton = nullptr; _viewButton = nullptr;
return; return;
@ -3114,7 +3104,7 @@ void Message::updateViewButtonExistence() {
colorIndex(), colorIndex(),
[=] { repaint(); }); [=] { repaint(); });
}; };
_viewButton = sponsored ? make(sponsored) : make(media); _viewButton = make(media);
} }
void Message::initLogEntryOriginal() { void Message::initLogEntryOriginal() {
@ -3200,7 +3190,7 @@ bool Message::hasFromName() const {
} }
bool Message::displayFromName() const { bool Message::displayFromName() const {
if (!hasFromName() || isAttachedToPrevious()) { if (!hasFromName() || isAttachedToPrevious() || data()->isSponsored()) {
return false; return false;
} }
return !Has<PsaTooltipState>(); return !Has<PsaTooltipState>();

View file

@ -13,9 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_view_button.h" #include "history/view/history_view_element.h"
#include "history/view/history_view_sponsored_click_handler.h"
#include "history/view/media/history_view_media_common.h" #include "history/view/media/history_view_media_common.h"
#include "history/view/media/history_view_theme_document.h" #include "history/view/media/history_view_theme_document.h"
#include "ui/image/image.h" #include "ui/image/image.h"
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/power_saving.h" #include "ui/power_saving.h"
#include "main/main_session.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_wall_paper.h" #include "data/data_wall_paper.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
@ -35,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo_media.h" #include "data/data_photo_media.h"
#include "data/data_file_click_handler.h" #include "data/data_file_click_handler.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_sponsored_messages.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
namespace HistoryView { namespace HistoryView {
@ -117,23 +119,7 @@ std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
: QString()); : QString());
} }
} // namespace [[nodiscard]] bool HasButton(not_null<WebPageData*> webpage) {
WebPage::WebPage(
not_null<Element*> parent,
not_null<WebPageData*> data,
MediaWebPageFlags flags)
: Media(parent)
, _st(st::historyPagePreview)
, _data(data)
, _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _title(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _description(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _flags(flags) {
history()->owner().registerWebPageView(_data, _parent);
}
bool WebPage::HasButton(not_null<WebPageData*> webpage) {
const auto type = webpage->type; const auto type = webpage->type;
return (type == WebPageType::Message) return (type == WebPageType::Message)
|| (type == WebPageType::Group) || (type == WebPageType::Group)
@ -154,6 +140,43 @@ bool WebPage::HasButton(not_null<WebPageData*> webpage) {
&& webpage->document->isWallPaper()); && webpage->document->isWallPaper());
} }
} // namespace
WebPage::WebPage(
not_null<Element*> parent,
not_null<WebPageData*> data,
MediaWebPageFlags flags)
: Media(parent)
, _st(st::historyPagePreview)
, _data(data)
, _sponsoredData([&]() -> std::optional<SponsoredData> {
if (!(flags & MediaWebPageFlag::Sponsored)) {
return std::nullopt;
}
const auto &data = _parent->data()->history()->owner();
const auto details = data.sponsoredMessages().lookupDetails(
_parent->data()->fullId());
auto result = std::make_optional<SponsoredData>();
result->buttonText = details.buttonText;
result->hasExternalLink = (details.externalLink == _data->url);
#ifdef _DEBUG
if (details.peer) {
#else
if (details.isForceUserpicDisplay && details.peer) {
#endif
result->peer = details.peer;
result->userpicView = details.peer->createUserpicView();
details.peer->loadUserpic();
}
return result;
}())
, _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _title(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _description(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _flags(flags) {
history()->owner().registerWebPageView(_data, _parent);
}
QSize WebPage::countOptimalSize() { QSize WebPage::countOptimalSize() {
if (_data->pendingTill || _data->failed) { if (_data->pendingTill || _data->failed) {
return { 0, 0 }; return { 0, 0 };
@ -165,6 +188,11 @@ QSize WebPage::countOptimalSize() {
if (HasButton(_data)) { if (HasButton(_data)) {
_openButton = PageToPhrase(_data); _openButton = PageToPhrase(_data);
_openButtonWidth = st::semiboldFont->width(_openButton); _openButtonWidth = st::semiboldFont->width(_openButton);
} else if (_sponsoredData) {
if (!_sponsoredData->buttonText.isEmpty()) {
_openButton = Ui::Text::Upper(_sponsoredData->buttonText);
_openButtonWidth = st::semiboldFont->width(_openButton);
}
} }
const auto padding = inBubblePadding() + innerMargin(); const auto padding = inBubblePadding() + innerMargin();
@ -183,7 +211,7 @@ QSize WebPage::countOptimalSize() {
} }
auto lineHeight = UnitedLineHeight(); auto lineHeight = UnitedLineHeight();
if (!_openl && !_data->url.isEmpty()) { if (!_openl && (!_data->url.isEmpty() || _sponsoredData)) {
const auto previewOfHiddenUrl = [&] { const auto previewOfHiddenUrl = [&] {
if (_data->type == WebPageType::BotApp) { if (_data->type == WebPageType::BotApp) {
// Bot Web Apps always show confirmation on hidden urls. // Bot Web Apps always show confirmation on hidden urls.
@ -233,6 +261,11 @@ QSize WebPage::countOptimalSize() {
_data->document, _data->document,
_parent->data()->fullId()); _parent->data()->fullId());
} }
if (_sponsoredData) {
_openl = SponsoredLink(_sponsoredData->hasExternalLink
? _data->url
: QString());
}
} }
// init layout // init layout
@ -375,13 +408,20 @@ QSize WebPage::countCurrentSize(int newWidth) {
auto newHeight = 0; auto newHeight = 0;
auto lineHeight = UnitedLineHeight(); auto lineHeight = UnitedLineHeight();
auto linesMax = isLogEntryOriginal() ? kMaxOriginalEntryLines : 5; auto linesMax = (_sponsoredData || isLogEntryOriginal())
? kMaxOriginalEntryLines
: 5;
auto siteNameHeight = _siteNameLines ? lineHeight : 0; auto siteNameHeight = _siteNameLines ? lineHeight : 0;
if (asArticle()) { const auto asSponsored = (!!_sponsoredData);
_pixh = linesMax * lineHeight; if (asArticle() || asSponsored) {
const auto article = asArticle();
constexpr auto kSponsoredUserpicLines = 2;
_pixh = (asSponsored ? kSponsoredUserpicLines : linesMax) * lineHeight;
do { do {
_pixw = articleThumbWidth(_data->photo, _pixh); _pixw = asSponsored ? _pixh : articleThumbWidth(_data->photo, _pixh);
auto wleft = innerWidth - st::webPagePhotoDelta - qMax(_pixw, lineHeight); auto wleft = asSponsored
? innerWidth - st::webPagePhotoDelta - qMax(_pixw, lineHeight)
: innerWidth;
newHeight = siteNameHeight; newHeight = siteNameHeight;
@ -494,7 +534,9 @@ void WebPage::ensurePhotoMediaCreated() const {
} }
bool WebPage::hasHeavyPart() const { bool WebPage::hasHeavyPart() const {
return _photoMedia || (_attach ? _attach->hasHeavyPart() : false); return _photoMedia
|| (_sponsoredData && !_sponsoredData->userpicView.null())
|| (_attach ? _attach->hasHeavyPart() : false);
} }
void WebPage::unloadHeavyPart() { void WebPage::unloadHeavyPart() {
@ -503,6 +545,9 @@ void WebPage::unloadHeavyPart() {
} }
_description.unloadPersistentAnimation(); _description.unloadPersistentAnimation();
_photoMedia = nullptr; _photoMedia = nullptr;
if (_sponsoredData) {
_sponsoredData->userpicView = Ui::PeerUserpicView();
}
} }
void WebPage::draw(Painter &p, const PaintContext &context) const { void WebPage::draw(Painter &p, const PaintContext &context) const {
@ -576,6 +621,21 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small)); st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small));
} }
paintw -= pw + st::webPagePhotoDelta; paintw -= pw + st::webPagePhotoDelta;
} else if (_sponsoredData && _sponsoredData->peer) {
const auto size = _pixh;
const auto sizeHq = size * style::DevicePixelRatio();
const auto userpicPos = QPoint(inner.left() + paintw - size, tshift);
const auto &peer = _sponsoredData->peer;
auto &view = _sponsoredData->userpicView;
if (const auto cloud = peer->userpicCloudImage(view)) {
Ui::ValidateUserpicCache(view, cloud, nullptr, sizeHq, true);
p.drawImage(QRect(userpicPos, QSize(size, size)), view.cached);
} else {
const auto r = sizeHq * Ui::ForumUserpicRadiusMultiplier();
const auto empty = peer->generateUserpicImage(view, sizeHq, r);
p.drawImage(QRect(userpicPos, QSize(size, size)), empty);
}
// paintw -= size + st::webPagePhotoDelta;
} }
if (_siteNameLines) { if (_siteNameLines) {
p.setPen(cache->icon); p.setPen(cache->icon);
@ -707,6 +767,9 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins(); const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height()); const auto full = QRect(0, 0, width(), height());
auto outer = full.marginsRemoved(inBubblePadding()); auto outer = full.marginsRemoved(inBubblePadding());
if (_sponsoredData) {
outer.translate(0, st::msgDateFont->height);
}
auto inner = outer.marginsRemoved(innerMargin()); auto inner = outer.marginsRemoved(innerMargin());
auto tshift = inner.top(); auto tshift = inner.top();
auto paintw = inner.width(); auto paintw = inner.width();
@ -790,7 +853,7 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
} }
} }
} }
if (!result.link && outer.contains(point)) { if ((!result.link || _sponsoredData) && outer.contains(point)) {
result.link = _openl; result.link = _openl;
} }
_lastPoint = point - outer.topLeft(); _lastPoint = point - outer.topLeft();

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "history/view/media/history_view_media.h" #include "history/view/media/history_view_media.h"
#include "ui/userpic_view.h"
namespace Data { namespace Data {
class Media; class Media;
@ -27,8 +28,6 @@ public:
not_null<WebPageData*> data, not_null<WebPageData*> data,
MediaWebPageFlags flags); MediaWebPageFlags flags);
[[nodiscard]] static bool HasButton(not_null<WebPageData*> data);
void refreshParentId(not_null<HistoryItem*> realParent) override; void refreshParentId(not_null<HistoryItem*> realParent) override;
void draw(Painter &p, const PaintContext &context) const override; void draw(Painter &p, const PaintContext &context) const override;
@ -131,6 +130,14 @@ private:
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia; mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
mutable std::unique_ptr<Ui::RippleAnimation> _ripple; mutable std::unique_ptr<Ui::RippleAnimation> _ripple;
struct SponsoredData final {
PeerData *peer = nullptr;
Ui::PeerUserpicView userpicView;
QString buttonText;
bool hasExternalLink = false;
};
mutable std::optional<SponsoredData> _sponsoredData;
int _dataVersion = -1; int _dataVersion = -1;
int _siteNameLines = 0; int _siteNameLines = 0;
int _descriptionLines = 0; int _descriptionLines = 0;