Changed behavior for sponsored messages to display them only when ready.

This commit is contained in:
23rd 2024-09-30 18:02:20 +03:00 committed by John Preston
parent e29c6d2f23
commit b753448052
4 changed files with 94 additions and 26 deletions

View file

@ -12,7 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_photo_media.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"
@ -69,16 +72,17 @@ void SponsoredMessages::clearOldRequests() {
} }
} }
bool SponsoredMessages::append(not_null<History*> history) { SponsoredMessages::AppendResult SponsoredMessages::append(
not_null<History*> history) {
const auto it = _data.find(history); const auto it = _data.find(history);
if (it == end(_data)) { if (it == end(_data)) {
return false; return SponsoredMessages::AppendResult::None;
} }
auto &list = it->second; auto &list = it->second;
if (list.showedAll if (list.showedAll
|| !TooEarlyForRequest(list.received) || !TooEarlyForRequest(list.received)
|| list.postsBetween) { || list.postsBetween) {
return false; return SponsoredMessages::AppendResult::None;
} }
const auto entryIt = ranges::find_if(list.entries, [](const Entry &e) { const auto entryIt = ranges::find_if(list.entries, [](const Entry &e) {
@ -86,19 +90,30 @@ bool SponsoredMessages::append(not_null<History*> history) {
}); });
if (entryIt == end(list.entries)) { if (entryIt == end(list.entries)) {
list.showedAll = true; list.showedAll = true;
return false; return SponsoredMessages::AppendResult::None;
}
if (const auto media = entryIt->documentMedia) {
const auto fullDuration = media->owner()->duration();
if (fullDuration <= 0) {
if (!media->loaded()) {
return SponsoredMessages::AppendResult::MediaLoading;
}
} else {
constexpr auto kEnoughDuration = float64(2000);
if ((kEnoughDuration / fullDuration) > media->progress()) {
return SponsoredMessages::AppendResult::MediaLoading;
}
}
}
if (entryIt->photoMedia && !entryIt->photoMedia->loaded()) {
return SponsoredMessages::AppendResult::MediaLoading;
} }
// SponsoredMessages::Details can be requested within
// the constructor of HistoryItem, so itemFullId is used as a key.
entryIt->itemFullId = FullMsgId(
history->peer->id,
_session->data().nextLocalMessageId());
entryIt->item.reset(history->addSponsoredMessage( entryIt->item.reset(history->addSponsoredMessage(
entryIt->itemFullId.msg, entryIt->itemFullId.msg,
entryIt->sponsored.from, entryIt->sponsored.from,
entryIt->sponsored.textWithEntities)); entryIt->sponsored.textWithEntities));
return true; return SponsoredMessages::AppendResult::Appended;
} }
void SponsoredMessages::inject( void SponsoredMessages::inject(
@ -221,8 +236,7 @@ void SponsoredMessages::request(not_null<History*> history, Fn<void()> done) {
const auto channel = history->peer->asChannel(); const auto channel = history->peer->asChannel();
Assert(channel != nullptr); Assert(channel != nullptr);
request.requestId = _session->api().request( request.requestId = _session->api().request(
MTPchannels_GetSponsoredMessages( MTPchannels_GetSponsoredMessages(channel->inputChannel)
channel->inputChannel)
).done([=](const MTPmessages_sponsoredMessages &result) { ).done([=](const MTPmessages_sponsoredMessages &result) {
parse(history, result); parse(history, result);
if (done) { if (done) {
@ -270,15 +284,15 @@ void SponsoredMessages::append(
const MTPSponsoredMessage &message) { const MTPSponsoredMessage &message) {
const auto &data = message.data(); const auto &data = message.data();
const auto randomId = data.vrandom_id().v; const auto randomId = data.vrandom_id().v;
auto mediaPhotoId = PhotoId(0); auto mediaPhoto = std::shared_ptr<Data::PhotoMedia>(nullptr);
auto mediaDocumentId = DocumentId(0); auto mediaDocument = std::shared_ptr<Data::DocumentMedia>(nullptr);
{ {
if (data.vmedia()) { if (data.vmedia()) {
data.vmedia()->match([&](const MTPDmessageMediaPhoto &media) { data.vmedia()->match([&](const MTPDmessageMediaPhoto &media) {
if (const auto tlPhoto = media.vphoto()) { if (const auto tlPhoto = media.vphoto()) {
tlPhoto->match([&](const MTPDphoto &data) { tlPhoto->match([&](const MTPDphoto &data) {
const auto p = history->owner().processPhoto(data); const auto p = history->owner().processPhoto(data);
mediaPhotoId = p->id; mediaPhoto = p->createMediaView();
}, [](const MTPDphotoEmpty &) { }, [](const MTPDphotoEmpty &) {
}); });
} }
@ -290,7 +304,7 @@ void SponsoredMessages::append(
|| d->isSilentVideo() || d->isSilentVideo()
|| d->isAnimation() || d->isAnimation()
|| d->isGifv()) { || d->isGifv()) {
mediaDocumentId = d->id; mediaDocument = d->createMediaView();
} }
}, [](const MTPDdocumentEmpty &) { }, [](const MTPDdocumentEmpty &) {
}); });
@ -306,8 +320,10 @@ void SponsoredMessages::append(
.photoId = data.vphoto() .photoId = data.vphoto()
? history->session().data().processPhoto(*data.vphoto())->id ? history->session().data().processPhoto(*data.vphoto())->id
: PhotoId(0), : PhotoId(0),
.mediaPhotoId = mediaPhotoId, .mediaPhotoId = (mediaPhoto ? mediaPhoto->owner()->id : PhotoId(0)),
.mediaDocumentId = mediaDocumentId, .mediaDocumentId = (mediaDocument
? mediaDocument->owner()->id
: DocumentId(0)),
.backgroundEmojiId = data.vcolor().has_value() .backgroundEmojiId = data.vcolor().has_value()
? data.vcolor()->data().vbackground_emoji_id().value_or_empty() ? data.vcolor()->data().vbackground_emoji_id().value_or_empty()
: uint64(0), : uint64(0),
@ -341,7 +357,31 @@ void SponsoredMessages::append(
.sponsorInfo = std::move(sponsorInfo), .sponsorInfo = std::move(sponsorInfo),
.additionalInfo = std::move(additionalInfo), .additionalInfo = std::move(additionalInfo),
}; };
list.entries.push_back({ nullptr, {}, std::move(sharedMessage) }); list.entries.push_back({
nullptr,
{},
std::move(sharedMessage),
mediaPhoto,
mediaDocument,
});
const auto fileOrigin = FullMsgId(
history->peer->id,
_session->data().nextLocalMessageId());
list.entries.back().itemFullId = fileOrigin;
if (mediaPhoto) {
mediaPhoto->owner()->load(
list.entries.back().itemFullId,
LoadFromCloudOrLocal,
true);
}
if (mediaDocument) {
mediaDocument->owner()->save(
fileOrigin,
QString(),
LoadFromCloudOrLocal,
true);
}
} }
void SponsoredMessages::clearItems(not_null<History*> history) { void SponsoredMessages::clearItems(not_null<History*> history) {

View file

@ -20,6 +20,9 @@ class Session;
namespace Data { namespace Data {
class DocumentMedia;
class PhotoMedia;
struct SponsoredReportResult final { struct SponsoredReportResult final {
using Id = QByteArray; using Id = QByteArray;
struct Option final { struct Option final {
@ -65,6 +68,11 @@ struct SponsoredMessage {
class SponsoredMessages final { class SponsoredMessages final {
public: public:
enum class AppendResult {
None,
Appended,
MediaLoading,
};
enum class State { enum class State {
None, None,
AppendToEnd, AppendToEnd,
@ -92,7 +100,7 @@ public:
[[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const; [[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const;
void clicked(const FullMsgId &fullId, bool isMedia, bool isFullscreen); void clicked(const FullMsgId &fullId, bool isMedia, bool isFullscreen);
[[nodiscard]] bool append(not_null<History*> history); [[nodiscard]] AppendResult append(not_null<History*> history);
void inject( void inject(
not_null<History*> history, not_null<History*> history,
MsgId injectAfterMsgId, MsgId injectAfterMsgId,
@ -114,6 +122,8 @@ private:
OwnedItem item; OwnedItem item;
FullMsgId itemFullId; FullMsgId itemFullId;
SponsoredMessage sponsored; SponsoredMessage sponsored;
std::shared_ptr<Data::PhotoMedia> photoMedia;
std::shared_ptr<Data::DocumentMedia> documentMedia;
}; };
struct List { struct List {
std::vector<Entry> entries; std::vector<Entry> entries;

View file

@ -321,10 +321,28 @@ HistoryWidget::HistoryWidget(
}), lifetime()); }), lifetime());
_scroll->addContentRequests( _scroll->addContentRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (_history if (_history && _history->loadedAtBottom()) {
&& _history->loadedAtBottom() using Result = Data::SponsoredMessages::AppendResult;
&& session().sponsoredMessages().append(_history)) { const auto tryToAppend = [=] {
_scroll->contentAdded(); const auto r = session().sponsoredMessages().append(_history);
if (r == Result::Appended) {
_scroll->contentAdded();
}
return r;
};
if (tryToAppend() == Result::MediaLoading) {
const auto sharedLifetime = std::make_shared<rpl::lifetime>();
session().downloaderTaskFinished(
) | rpl::start_with_next([=, weak = Ui::MakeWeak(this)] {
if (const auto strong = weak.data()) {
if (tryToAppend() != Result::MediaLoading) {
sharedLifetime->destroy();
}
} else {
sharedLifetime->destroy();
}
}, *sharedLifetime);
}
} }
}, lifetime()); }, lifetime());

View file

@ -847,8 +847,8 @@ void DraftOptionsBox(
if (state->quote.current().overflown) { if (state->quote.current().overflown) {
show->showToast({ show->showToast({
.title = tr::lng_reply_quote_long_title(tr::now), .title = tr::lng_reply_quote_long_title(tr::now),
.text = tr::lng_reply_quote_long_text(tr::now), .text = { tr::lng_reply_quote_long_text(tr::now) },
}); });
} else { } else {
finish(resolveReply(), state->webpage); finish(resolveReply(), state->webpage);
} }