Added support of simplified constructor for MTP sponsored message.

This commit is contained in:
23rd 2024-04-12 02:42:18 +03:00 committed by John Preston
parent ac15990b48
commit 72b274a2bf
8 changed files with 85 additions and 229 deletions

View File

@ -9,8 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_text_entities.h"
#include "apiwrap.h"
#include "data/data_bot_app.h"
#include "core/click_handler_types.h"
#include "data/data_channel.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/history.h"
@ -257,94 +258,23 @@ void SponsoredMessages::append(
const MTPSponsoredMessage &message) {
const auto &data = message.data();
const auto randomId = data.vrandom_id().v;
const auto hash = qs(data.vchat_invite_hash().value_or_empty());
const auto makeFrom = [&](
not_null<PeerData*> peer,
bool exactPost = false) {
const auto channel = peer->asChannel();
return SponsoredFrom{
.peer = peer,
.title = peer->name(),
.isBroadcast = (channel && channel->isBroadcast()),
.isMegagroup = (channel && channel->isMegagroup()),
.isChannel = (channel != nullptr),
.isPublic = (channel && channel->isPublic()),
.isExactPost = exactPost,
.isRecommended = data.is_recommended(),
.isForceUserpicDisplay = data.is_show_peer_photo(),
.buttonText = qs(data.vbutton_text().value_or_empty()),
.canReport = data.is_can_report(),
};
const auto from = SponsoredFrom{
.title = qs(data.vtitle()),
.link = qs(data.vurl()),
.buttonText = qs(data.vbutton_text()),
.photoId = data.vphoto()
? history->session().data().processPhoto(*data.vphoto())->id
: PhotoId(0),
.backgroundEmojiId = data.vcolor().has_value()
? data.vcolor()->data().vbackground_emoji_id().value_or_empty()
: uint64(0),
.colorIndex = uint8(data.vcolor().has_value()
? data.vcolor()->data().vcolor().value_or_empty()
: 0),
.isLinkInternal = !UrlRequiresConfirmation(qs(data.vurl())),
.isRecommended = data.is_recommended(),
.canReport = data.is_can_report(),
};
const auto externalLink = data.vwebpage()
? qs(data.vwebpage()->data().vurl())
: QString();
const auto from = [&]() -> SponsoredFrom {
if (const auto webpage = data.vwebpage()) {
const auto &data = webpage->data();
const auto photoId = data.vphoto()
? _session->data().processPhoto(*data.vphoto())->id
: PhotoId(0);
return SponsoredFrom{
.title = qs(data.vsite_name()),
.externalLink = externalLink,
.webpageOrBotPhotoId = photoId,
.isForceUserpicDisplay = message.data().is_show_peer_photo(),
.canReport = message.data().is_can_report(),
};
} else if (const auto fromId = data.vfrom_id()) {
const auto peerId = peerFromMTP(*fromId);
auto result = makeFrom(
_session->data().peer(peerId),
(data.vchannel_post() != nullptr));
const auto user = result.peer->asUser();
if (user && user->isBot()) {
const auto botAppData = data.vapp()
? _session->data().processBotApp(peerId, *data.vapp())
: nullptr;
result.botLinkInfo = Window::PeerByLinkInfo{
.usernameOrId = user->username(),
.resolveType = botAppData
? Window::ResolveType::BotApp
: data.vstart_param()
? Window::ResolveType::BotStart
: Window::ResolveType::Default,
.startToken = qs(data.vstart_param().value_or_empty()),
.botAppName = botAppData
? botAppData->shortName
: QString(),
};
result.webpageOrBotPhotoId = (botAppData && botAppData->photo)
? botAppData->photo->id
: PhotoId(0);
}
return result;
}
Assert(data.vchat_invite());
return data.vchat_invite()->match([&](const MTPDchatInvite &data) {
return SponsoredFrom{
.title = qs(data.vtitle()),
.isBroadcast = data.is_broadcast(),
.isMegagroup = data.is_megagroup(),
.isChannel = data.is_channel(),
.isPublic = data.is_public(),
.isForceUserpicDisplay = message.data().is_show_peer_photo(),
.canReport = message.data().is_can_report(),
};
}, [&](const MTPDchatInviteAlready &data) {
const auto chat = _session->data().processChat(data.vchat());
if (const auto channel = chat->asChannel()) {
channel->clearInvitePeek();
}
return makeFrom(chat);
}, [&](const MTPDchatInvitePeek &data) {
const auto chat = _session->data().processChat(data.vchat());
if (const auto channel = chat->asChannel()) {
channel->setInvitePeek(hash, data.vexpires().v);
}
return makeFrom(chat);
});
}();
auto sponsorInfo = data.vsponsor_info()
? tr::lng_sponsored_info_submenu(
tr::now,
@ -364,9 +294,7 @@ void SponsoredMessages::append(
data.ventities().value_or_empty()),
},
.history = history,
.msgId = data.vchannel_post().value_or_empty(),
.chatInviteHash = hash,
.externalLink = externalLink,
.link = from.link,
.sponsorInfo = std::move(sponsorInfo),
.additionalInfo = std::move(additionalInfo),
};
@ -438,7 +366,6 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
return {};
}
const auto &data = entryPtr->sponsored;
const auto &hash = data.chatInviteHash;
using InfoList = std::vector<TextWithEntities>;
auto info = (!data.sponsorInfo.text.isEmpty()
@ -450,20 +377,13 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
? InfoList{ data.additionalInfo }
: InfoList{};
return {
.hash = hash.isEmpty() ? std::nullopt : std::make_optional(hash),
.peer = data.from.peer,
.msgId = data.msgId,
.info = std::move(info),
.externalLink = data.externalLink,
.isForceUserpicDisplay = data.from.isForceUserpicDisplay,
.buttonText = !data.from.buttonText.isEmpty()
? data.from.buttonText
: !data.externalLink.isEmpty()
? tr::lng_view_button_external_link(tr::now)
: data.from.botLinkInfo
? tr::lng_view_button_bot(tr::now)
: QString(),
.botLinkInfo = data.from.botLinkInfo,
.link = data.link,
.photoId = data.from.photoId,
.buttonText = data.from.buttonText,
.backgroundEmojiId = data.from.backgroundEmojiId,
.colorIndex = data.from.colorIndex,
.isLinkInternal = data.from.isLinkInternal,
.canReport = data.from.canReport,
};
}

View File

@ -40,19 +40,14 @@ struct SponsoredReportResult final {
};
struct SponsoredFrom {
PeerData *peer = nullptr;
QString title;
bool isBroadcast = false;
bool isMegagroup = false;
bool isChannel = false;
bool isPublic = false;
std::optional<Window::PeerByLinkInfo> botLinkInfo;
bool isExactPost = false;
bool isRecommended = false;
QString externalLink;
PhotoId webpageOrBotPhotoId = PhotoId(0);
bool isForceUserpicDisplay = false;
QString link;
QString buttonText;
PhotoId photoId = PhotoId(0);
uint64 backgroundEmojiId = 0;
uint8 colorIndex : 6 = 0;
bool isLinkInternal = false;
bool isRecommended = false;
bool canReport = false;
};
@ -61,9 +56,7 @@ struct SponsoredMessage {
SponsoredFrom from;
TextWithEntities textWithEntities;
History *history = nullptr;
MsgId msgId;
QString chatInviteHash;
QString externalLink;
QString link;
TextWithEntities sponsorInfo;
TextWithEntities additionalInfo;
};
@ -76,14 +69,13 @@ public:
InjectToMiddle,
};
struct Details {
std::optional<QString> hash;
PeerData *peer = nullptr;
MsgId msgId;
std::vector<TextWithEntities> info;
QString externalLink;
bool isForceUserpicDisplay = false;
QString link;
QString buttonText;
std::optional<Window::PeerByLinkInfo> botLinkInfo;
PhotoId photoId = PhotoId(0);
uint64 backgroundEmojiId = 0;
uint8 colorIndex : 6 = 0;
bool isLinkInternal = false;
bool canReport = false;
};
using RandomId = QByteArray;

View File

@ -641,32 +641,18 @@ HistoryItem::HistoryItem(
? injectedAfter->date()
: 0),
}) {
const auto webPageType = !from.externalLink.isEmpty()
? WebPageType::None
: from.isExactPost
? WebPageType::Message
: (from.botLinkInfo && !from.botLinkInfo->botAppName.isEmpty())
? WebPageType::BotApp
: from.botLinkInfo
? WebPageType::Bot
: 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,
WebPageType::None,
from.link,
from.link,
from.isRecommended
? tr::lng_recommended_message_title(tr::now)
: tr::lng_sponsored_message_title(tr::now),
from.title,
textWithEntities,
(from.webpageOrBotPhotoId
? history->owner().photo(from.webpageOrBotPhotoId).get()
(from.photoId
? history->owner().photo(from.photoId).get()
: nullptr),
nullptr,
WebPageCollage(),

View File

@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_element.h"
#include "api/api_chat_invite.h"
#include "history/view/history_view_service_message.h"
#include "history/view/history_view_message.h"
#include "history/view/media/history_view_media_grouped.h"
@ -27,10 +26,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "core/core_settings.h"
#include "core/click_handler_types.h"
#include "core/file_utilities.h"
#include "core/ui_integration.h"
#include "main/main_session.h"
#include "main/main_domain.h"
#include "chat_helpers/stickers_emoji_pack.h"
#include "window/window_session_controller.h"
#include "ui/effects/path_shift_gradient.h"
@ -1099,29 +1096,7 @@ ClickHandlerPtr Element::fromLink() const {
return _fromLink;
}
const auto item = data();
if (item->isSponsored()) {
const auto session = &item->history()->session();
_fromLink = std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
if (context.button != Qt::LeftButton) {
return;
}
const auto my = context.other.value<ClickHandlerContext>();
if (const auto window = ContextOrSessionWindow(my, session)) {
auto &sponsored = session->sponsoredMessages();
const auto itemId = my.itemId ? my.itemId : item->fullId();
const auto details = sponsored.lookupDetails(itemId);
if (!details.externalLink.isEmpty()) {
File::OpenUrl(details.externalLink);
} else if (const auto &hash = details.hash) {
Api::CheckChatInvite(window, *hash);
} else if (const auto peer = details.peer) {
window->showPeerInfo(peer);
}
}
});
return _fromLink;
} else if (const auto from = item->displayFrom()) {
if (const auto from = item->displayFrom()) {
_fromLink = std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
if (context.button != Qt::LeftButton) {

View File

@ -7,53 +7,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_sponsored_click_handler.h"
#include "api/api_chat_invite.h"
#include "core/click_handler_types.h"
#include "core/file_utilities.h"
#include "data/components/sponsored_messages.h"
#include "data/data_session.h"
#include "main/main_session.h"
#include "window/window_session_controller.h"
namespace HistoryView {
ClickHandlerPtr SponsoredLink(const QString &externalLink) {
if (!externalLink.isEmpty()) {
class ClickHandler : public UrlClickHandler {
public:
using UrlClickHandler::UrlClickHandler;
ClickHandlerPtr SponsoredLink(const QString &link, bool isInternal) {
class ClickHandler final : public UrlClickHandler {
public:
ClickHandler(const QString &link, bool isInternal)
: UrlClickHandler(link, false)
, _isInternal(isInternal) {
}
QString copyToClipboardContextItemText() const override {
return QString();
}
QString copyToClipboardContextItemText() const override final {
return QString();
}
};
QString tooltip() const override final {
return _isInternal ? QString() : url();
}
return std::make_shared<ClickHandler>(externalLink, false);
} else {
return std::make_shared<LambdaClickHandler>([](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
const auto controller = my.sessionWindow.get();
if (!controller) {
return;
}
const auto &session = controller->session();
const auto details = session.sponsoredMessages().lookupDetails(
my.itemId);
if (!details.externalLink.isEmpty()) {
File::OpenUrl(details.externalLink);
} else if (details.hash) {
Api::CheckChatInvite(controller, *details.hash);
} else if (details.botLinkInfo) {
controller->showPeerByLink(*details.botLinkInfo);
} else if (details.peer) {
controller->showPeerHistory(
details.peer,
Window::SectionShow::Way::Forward,
details.msgId);
}
});
}
private:
const bool _isInternal;
};
return std::make_shared<ClickHandler>(link, isInternal);
}
} // namespace HistoryView

View File

@ -12,6 +12,7 @@ class ClickHandler;
namespace HistoryView {
[[nodiscard]] std::shared_ptr<ClickHandler> SponsoredLink(
const QString &externalLink);
const QString &link,
bool isInternal);
} // namespace HistoryView

View File

@ -232,17 +232,10 @@ WebPage::WebPage(
_parent->data()->fullId());
auto result = std::make_optional<SponsoredData>();
result->buttonText = details.buttonText;
result->hasExternalLink = (details.externalLink == _data->url);
result->isLinkInternal = details.isLinkInternal;
result->backgroundEmojiId = details.backgroundEmojiId;
result->colorIndex = details.colorIndex;
result->canReport = details.canReport;
#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())
@ -345,9 +338,9 @@ QSize WebPage::countOptimalSize() {
_parent->data()->fullId());
}
if (_sponsoredData) {
_openl = SponsoredLink(_sponsoredData->hasExternalLink
? _data->url
: QString());
_openl = SponsoredLink(
_data->url,
_sponsoredData->isLinkInternal);
if (_sponsoredData->canReport) {
_sponsoredData->hintLink = AboutSponsoredClickHandler();
@ -683,14 +676,23 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
auto tshift = inner.top();
auto paintw = inner.width();
const auto asSponsored = (!!_sponsoredData);
const auto selected = context.selected();
const auto view = parent();
const auto from = view->data()->contentColorsFrom();
const auto colorIndex = from ? from->colorIndex() : view->colorIndex();
const auto colorIndex = (asSponsored && _sponsoredData->colorIndex)
? _sponsoredData->colorIndex
: from
? from->colorIndex()
: view->colorIndex();
const auto cache = context.outbg
? stm->replyCache[st->colorPatternIndex(colorIndex)].get()
: st->coloredReplyCache(selected, colorIndex).get();
const auto backgroundEmojiId = from
const auto backgroundEmojiId = (asSponsored
&& _sponsoredData->backgroundEmojiId)
? _sponsoredData->backgroundEmojiId
: from
? from->backgroundEmojiId()
: DocumentId();
const auto backgroundEmoji = backgroundEmojiId
@ -724,8 +726,6 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
}
}
const auto asSponsored = (!!_sponsoredData);
auto lineHeight = UnitedLineHeight();
if (asArticle()) {
ensurePhotoMediaCreated();

View File

@ -134,7 +134,10 @@ private:
PeerData *peer = nullptr;
Ui::PeerUserpicView userpicView;
QString buttonText;
bool hasExternalLink = false;
bool isLinkInternal = false;
uint64 backgroundEmojiId = 0;
uint8 colorIndex : 6 = 0;
bool canReport = false;
QSize hintSize;