mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-26 07:23:02 +02:00
Track shown sponsored in video.
This commit is contained in:
parent
e5ca9e4c39
commit
284cbda7c0
8 changed files with 345 additions and 32 deletions
|
@ -1257,6 +1257,8 @@ PRIVATE
|
||||||
media/view/media_view_playback_controls.h
|
media/view/media_view_playback_controls.h
|
||||||
media/view/media_view_playback_progress.cpp
|
media/view/media_view_playback_progress.cpp
|
||||||
media/view/media_view_playback_progress.h
|
media/view/media_view_playback_progress.h
|
||||||
|
media/view/media_view_playback_sponsored.cpp
|
||||||
|
media/view/media_view_playback_sponsored.h
|
||||||
media/system_media_controls_manager.h
|
media/system_media_controls_manager.h
|
||||||
media/system_media_controls_manager.cpp
|
media/system_media_controls_manager.cpp
|
||||||
menu/menu_antispam_validator.cpp
|
menu/menu_antispam_validator.cpp
|
||||||
|
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Data {
|
namespace Data {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kMs = crl::time(1000);
|
||||||
constexpr auto kRequestTimeLimit = 5 * 60 * crl::time(1000);
|
constexpr auto kRequestTimeLimit = 5 * 60 * crl::time(1000);
|
||||||
|
|
||||||
const auto kFlaggedPreload = ((MediaPreload*)quintptr(0x01));
|
const auto kFlaggedPreload = ((MediaPreload*)quintptr(0x01));
|
||||||
|
@ -288,7 +289,7 @@ void SponsoredMessages::request(not_null<History*> history, Fn<void()> done) {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SponsoredMessages::request(
|
void SponsoredMessages::requestForVideo(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
Fn<void(SponsoredForVideo)> done) {
|
Fn<void(SponsoredForVideo)> done) {
|
||||||
Expects(done != nullptr);
|
Expects(done != nullptr);
|
||||||
|
@ -297,14 +298,23 @@ void SponsoredMessages::request(
|
||||||
done({});
|
done({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto id = item->fullId();
|
const auto peer = item->history()->peer;
|
||||||
auto &request = _requestsForVideo[id];
|
auto &request = _requestsForVideo[peer];
|
||||||
|
if (TooEarlyForRequest(request.lastReceived)) {
|
||||||
|
auto prepared = prepareForVideo(peer);
|
||||||
|
if (prepared.list.empty()
|
||||||
|
|| prepared.state.itemIndex < prepared.list.size()
|
||||||
|
|| prepared.state.leftTillShow > 0) {
|
||||||
|
done(std::move(prepared));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.callbacks.push_back(std::move(done));
|
||||||
if (request.requestId) {
|
if (request.requestId) {
|
||||||
done(prepareForVideo(id));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto it = _dataForVideo.find(id);
|
const auto it = _dataForVideo.find(peer);
|
||||||
if (it != end(_dataForVideo)) {
|
if (it != end(_dataForVideo)) {
|
||||||
auto &list = it->second;
|
auto &list = it->second;
|
||||||
// Don't rebuild currently displayed messages.
|
// Don't rebuild currently displayed messages.
|
||||||
|
@ -316,21 +326,41 @@ void SponsoredMessages::request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto finish = [=] {
|
||||||
|
const auto i = _requestsForVideo.find(peer);
|
||||||
|
if (i != end(_requestsForVideo)) {
|
||||||
|
for (const auto &callback : base::take(i->second.callbacks)) {
|
||||||
|
callback(prepareForVideo(peer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
using Flag = MTPmessages_GetSponsoredMessages::Flag;
|
using Flag = MTPmessages_GetSponsoredMessages::Flag;
|
||||||
request.requestId = _session->api().request(
|
request.requestId = _session->api().request(
|
||||||
MTPmessages_GetSponsoredMessages(
|
MTPmessages_GetSponsoredMessages(
|
||||||
MTP_flags(Flag::f_msg_id),
|
MTP_flags(Flag::f_msg_id),
|
||||||
item->history()->peer->input,
|
peer->input,
|
||||||
MTP_int(item->id.bare))
|
MTP_int(item->id.bare))
|
||||||
).done([=](const MTPmessages_sponsoredMessages &result) {
|
).done([=](const MTPmessages_sponsoredMessages &result) {
|
||||||
parse(id, result);
|
parseForVideo(peer, result);
|
||||||
done(prepareForVideo(id));
|
finish();
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
_requestsForVideo.remove(id);
|
_requestsForVideo.remove(peer);
|
||||||
done({});
|
finish();
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SponsoredMessages::updateForVideo(
|
||||||
|
FullMsgId itemId,
|
||||||
|
SponsoredForVideoState state) {
|
||||||
|
if (state.initial()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto i = _dataForVideo.find(_session->data().peer(itemId.peer));
|
||||||
|
if (i != end(_dataForVideo)) {
|
||||||
|
i->second.state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SponsoredMessages::parse(
|
void SponsoredMessages::parse(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
const MTPmessages_sponsoredMessages &list) {
|
const MTPmessages_sponsoredMessages &list) {
|
||||||
|
@ -366,10 +396,10 @@ void SponsoredMessages::parse(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SponsoredMessages::parse(
|
void SponsoredMessages::parseForVideo(
|
||||||
FullMsgId itemId,
|
not_null<PeerData*> peer,
|
||||||
const MTPmessages_sponsoredMessages &list) {
|
const MTPmessages_sponsoredMessages &list) {
|
||||||
auto &request = _requestsForVideo[itemId];
|
auto &request = _requestsForVideo[peer];
|
||||||
request.lastReceived = crl::now();
|
request.lastReceived = crl::now();
|
||||||
request.requestId = 0;
|
request.requestId = 0;
|
||||||
if (!_clearTimer.isActive()) {
|
if (!_clearTimer.isActive()) {
|
||||||
|
@ -380,24 +410,25 @@ void SponsoredMessages::parse(
|
||||||
_session->data().processUsers(data.vusers());
|
_session->data().processUsers(data.vusers());
|
||||||
_session->data().processChats(data.vchats());
|
_session->data().processChats(data.vchats());
|
||||||
|
|
||||||
const auto history = _session->data().history(itemId.peer);
|
const auto history = _session->data().history(peer);
|
||||||
const auto &messages = data.vmessages().v;
|
const auto &messages = data.vmessages().v;
|
||||||
auto &list = _dataForVideo.emplace(itemId).first->second;
|
auto &list = _dataForVideo.emplace(peer).first->second;
|
||||||
list.entries.clear();
|
list.entries.clear();
|
||||||
list.received = crl::now();
|
list.received = crl::now();
|
||||||
list.startDelay = data.vstart_delay().value_or_empty();
|
list.startDelay = 2000;AssertIsDebug()// data.vstart_delay().value_or_empty() * kMs;
|
||||||
list.betweenDelay = data.vbetween_delay().value_or_empty();
|
list.betweenDelay = 3000;//data.vbetween_delay().value_or_empty() * kMs;
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
append([=] {
|
append([=] {
|
||||||
return &_dataForVideo[itemId].entries;
|
return &_dataForVideo[peer].entries;
|
||||||
}, history, message);
|
}, history, message);
|
||||||
}
|
}
|
||||||
}, [](const MTPDmessages_sponsoredMessagesEmpty &) {
|
}, [](const MTPDmessages_sponsoredMessagesEmpty &) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SponsoredForVideo SponsoredMessages::prepareForVideo(FullMsgId itemId) {
|
SponsoredForVideo SponsoredMessages::prepareForVideo(
|
||||||
const auto i = _dataForVideo.find(itemId);
|
not_null<PeerData*> peer) {
|
||||||
|
const auto i = _dataForVideo.find(peer);
|
||||||
if (i == end(_dataForVideo) || i->second.entries.empty()) {
|
if (i == end(_dataForVideo) || i->second.entries.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -407,6 +438,7 @@ SponsoredForVideo SponsoredMessages::prepareForVideo(FullMsgId itemId) {
|
||||||
) | ranges::to_vector,
|
) | ranges::to_vector,
|
||||||
.startDelay = i->second.startDelay,
|
.startDelay = i->second.startDelay,
|
||||||
.betweenDelay = i->second.betweenDelay,
|
.betweenDelay = i->second.betweenDelay,
|
||||||
|
.state = i->second.state,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,6 +567,8 @@ void SponsoredMessages::append(
|
||||||
.link = from.link,
|
.link = from.link,
|
||||||
.sponsorInfo = std::move(sponsorInfo),
|
.sponsorInfo = std::move(sponsorInfo),
|
||||||
.additionalInfo = std::move(additionalInfo),
|
.additionalInfo = std::move(additionalInfo),
|
||||||
|
.durationMin = 3000, AssertIsDebug()//data.vmin_display_duration().value_or_empty() * kMs,
|
||||||
|
.durationMax = 5000,//data.vmax_display_duration().value_or_empty() * kMs,
|
||||||
};
|
};
|
||||||
const auto itemId = FullMsgId(
|
const auto itemId = FullMsgId(
|
||||||
history->peer->id,
|
history->peer->id,
|
||||||
|
|
|
@ -71,6 +71,8 @@ struct SponsoredMessage {
|
||||||
QString link;
|
QString link;
|
||||||
TextWithEntities sponsorInfo;
|
TextWithEntities sponsorInfo;
|
||||||
TextWithEntities additionalInfo;
|
TextWithEntities additionalInfo;
|
||||||
|
crl::time durationMin = 0;
|
||||||
|
crl::time durationMax = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SponsoredMessageDetails {
|
struct SponsoredMessageDetails {
|
||||||
|
@ -92,10 +94,21 @@ struct SponsoredReportAction {
|
||||||
Fn<void(Data::SponsoredReportResult)>)> callback;
|
Fn<void(Data::SponsoredReportResult)>)> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SponsoredForVideoState {
|
||||||
|
int itemIndex = 0;
|
||||||
|
crl::time leftTillShow = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] bool initial() const {
|
||||||
|
return !itemIndex && !leftTillShow;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SponsoredForVideo {
|
struct SponsoredForVideo {
|
||||||
std::vector<SponsoredMessage> list;
|
std::vector<SponsoredMessage> list;
|
||||||
crl::time startDelay = 0;
|
crl::time startDelay = 0;
|
||||||
crl::time betweenDelay = 0;
|
crl::time betweenDelay = 0;
|
||||||
|
|
||||||
|
SponsoredForVideoState state;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SponsoredMessages final {
|
class SponsoredMessages final {
|
||||||
|
@ -120,9 +133,12 @@ public:
|
||||||
[[nodiscard]] bool canHaveFor(not_null<HistoryItem*> item) const;
|
[[nodiscard]] bool canHaveFor(not_null<HistoryItem*> item) const;
|
||||||
[[nodiscard]] bool isTopBarFor(not_null<History*> history) const;
|
[[nodiscard]] bool isTopBarFor(not_null<History*> history) const;
|
||||||
void request(not_null<History*> history, Fn<void()> done);
|
void request(not_null<History*> history, Fn<void()> done);
|
||||||
void request(
|
void requestForVideo(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
Fn<void(SponsoredForVideo)> done);
|
Fn<void(SponsoredForVideo)> done);
|
||||||
|
void updateForVideo(
|
||||||
|
FullMsgId itemId,
|
||||||
|
SponsoredForVideoState state);
|
||||||
void clearItems(not_null<History*> history);
|
void clearItems(not_null<History*> history);
|
||||||
[[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const;
|
[[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const;
|
||||||
[[nodiscard]] Details lookupDetails(
|
[[nodiscard]] Details lookupDetails(
|
||||||
|
@ -181,23 +197,30 @@ private:
|
||||||
crl::time received = 0;
|
crl::time received = 0;
|
||||||
crl::time startDelay = 0;
|
crl::time startDelay = 0;
|
||||||
crl::time betweenDelay = 0;
|
crl::time betweenDelay = 0;
|
||||||
|
SponsoredForVideoState state;
|
||||||
};
|
};
|
||||||
struct Request {
|
struct Request {
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
crl::time lastReceived = 0;
|
crl::time lastReceived = 0;
|
||||||
};
|
};
|
||||||
|
struct RequestForVideo {
|
||||||
|
std::vector<Fn<void(SponsoredForVideo)>> callbacks;
|
||||||
|
mtpRequestId requestId = 0;
|
||||||
|
crl::time lastReceived = 0;
|
||||||
|
};
|
||||||
|
|
||||||
void parse(
|
void parse(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
const MTPmessages_sponsoredMessages &list);
|
const MTPmessages_sponsoredMessages &list);
|
||||||
void parse(
|
void parseForVideo(
|
||||||
FullMsgId itemId,
|
not_null<PeerData*> peer,
|
||||||
const MTPmessages_sponsoredMessages &list);
|
const MTPmessages_sponsoredMessages &list);
|
||||||
void append(
|
void append(
|
||||||
Fn<not_null<std::vector<Entry>*>()> entries,
|
Fn<not_null<std::vector<Entry>*>()> entries,
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
const MTPSponsoredMessage &message);
|
const MTPSponsoredMessage &message);
|
||||||
[[nodiscard]] SponsoredForVideo prepareForVideo(FullMsgId itemId);
|
[[nodiscard]] SponsoredForVideo prepareForVideo(
|
||||||
|
not_null<PeerData*> peer);
|
||||||
void clearOldRequests();
|
void clearOldRequests();
|
||||||
|
|
||||||
const Entry *find(const FullMsgId &fullId) const;
|
const Entry *find(const FullMsgId &fullId) const;
|
||||||
|
@ -209,8 +232,8 @@ private:
|
||||||
base::flat_map<not_null<History*>, Request> _requests;
|
base::flat_map<not_null<History*>, Request> _requests;
|
||||||
base::flat_map<RandomId, Request> _viewRequests;
|
base::flat_map<RandomId, Request> _viewRequests;
|
||||||
|
|
||||||
base::flat_map<FullMsgId, ListForVideo> _dataForVideo;
|
base::flat_map<not_null<PeerData*>, ListForVideo> _dataForVideo;
|
||||||
base::flat_map<FullMsgId, Request> _requestsForVideo;
|
base::flat_map<not_null<PeerData*>, RequestForVideo> _requestsForVideo;
|
||||||
|
|
||||||
rpl::event_stream<FullMsgId> _itemRemoved;
|
rpl::event_stream<FullMsgId> _itemRemoved;
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/view/media_view_pip.h"
|
#include "media/view/media_view_pip.h"
|
||||||
#include "media/view/media_view_overlay_raster.h"
|
#include "media/view/media_view_overlay_raster.h"
|
||||||
#include "media/view/media_view_overlay_opengl.h"
|
#include "media/view/media_view_overlay_opengl.h"
|
||||||
|
#include "media/view/media_view_playback_sponsored.h"
|
||||||
#include "media/stories/media_stories_share.h"
|
#include "media/stories/media_stories_share.h"
|
||||||
#include "media/stories/media_stories_view.h"
|
#include "media/stories/media_stories_view.h"
|
||||||
#include "media/streaming/media_streaming_document.h"
|
#include "media/streaming/media_streaming_document.h"
|
||||||
|
@ -335,6 +336,7 @@ struct OverlayWidget::Streamed {
|
||||||
|
|
||||||
Streaming::Instance instance;
|
Streaming::Instance instance;
|
||||||
std::unique_ptr<PlaybackControls> controls;
|
std::unique_ptr<PlaybackControls> controls;
|
||||||
|
std::unique_ptr<PlaybackSponsored> sponsored;
|
||||||
std::unique_ptr<base::PowerSaveBlocker> powerSaveBlocker;
|
std::unique_ptr<base::PowerSaveBlocker> powerSaveBlocker;
|
||||||
|
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
|
@ -4069,6 +4071,9 @@ void OverlayWidget::initStreamingThumbnail() {
|
||||||
|
|
||||||
void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
||||||
_streamed->ready = true;
|
_streamed->ready = true;
|
||||||
|
if (const auto sponsored = _streamed->sponsored.get()) {
|
||||||
|
sponsored->start();
|
||||||
|
}
|
||||||
if (videoShown()) {
|
if (videoShown()) {
|
||||||
applyVideoSize();
|
applyVideoSize();
|
||||||
_streamedQualityChangeFrame = QImage();
|
_streamedQualityChangeFrame = QImage();
|
||||||
|
@ -4090,6 +4095,7 @@ void OverlayWidget::applyVideoSize() {
|
||||||
|
|
||||||
bool OverlayWidget::createStreamingObjects() {
|
bool OverlayWidget::createStreamingObjects() {
|
||||||
Expects(_photo || _document);
|
Expects(_photo || _document);
|
||||||
|
Expects(!_streamed);
|
||||||
|
|
||||||
const auto origin = fileOrigin();
|
const auto origin = fileOrigin();
|
||||||
const auto callback = [=] { waitingAnimationCallback(); };
|
const auto callback = [=] { waitingAnimationCallback(); };
|
||||||
|
@ -4122,6 +4128,15 @@ bool OverlayWidget::createStreamingObjects() {
|
||||||
_body,
|
_body,
|
||||||
static_cast<PlaybackControls::Delegate*>(this));
|
static_cast<PlaybackControls::Delegate*>(this));
|
||||||
_streamed->controls->show();
|
_streamed->controls->show();
|
||||||
|
_streamed->sponsored = PlaybackSponsored::Has(_message)
|
||||||
|
? std::make_unique<PlaybackSponsored>(_body, _message)
|
||||||
|
: nullptr;
|
||||||
|
if (const auto sponsored = _streamed->sponsored.get()) {
|
||||||
|
_layerBg->layerShownValue(
|
||||||
|
) | rpl::start_with_next([=](bool shown) {
|
||||||
|
sponsored->setPaused(shown);
|
||||||
|
}, sponsored->lifetime());
|
||||||
|
}
|
||||||
refreshClipControllerGeometry();
|
refreshClipControllerGeometry();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -78,6 +78,7 @@ struct ContentLayout;
|
||||||
|
|
||||||
namespace Media::View {
|
namespace Media::View {
|
||||||
|
|
||||||
|
class PlaybackSponsored;
|
||||||
class GroupThumbs;
|
class GroupThumbs;
|
||||||
class Pip;
|
class Pip;
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,13 @@ class MediaSlider;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Media {
|
namespace Media::Player {
|
||||||
namespace Player {
|
|
||||||
struct TrackState;
|
struct TrackState;
|
||||||
class SettingsButton;
|
class SettingsButton;
|
||||||
class SpeedController;
|
class SpeedController;
|
||||||
} // namespace Player
|
} // namespace Media::Player
|
||||||
|
|
||||||
namespace View {
|
namespace Media::View {
|
||||||
|
|
||||||
class PlaybackProgress;
|
class PlaybackProgress;
|
||||||
|
|
||||||
|
@ -131,5 +130,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace View
|
} // namespace Media::View
|
||||||
} // namespace Media
|
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "media/view/media_view_playback_sponsored.h"
|
||||||
|
|
||||||
|
#include "data/components/sponsored_messages.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
|
||||||
|
namespace Media::View {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kStartDelayMin = crl::time(1000);
|
||||||
|
constexpr auto kDurationMin = 5 * crl::time(1000);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
PlaybackSponsored::PlaybackSponsored(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<HistoryItem*> item)
|
||||||
|
: _parent(parent)
|
||||||
|
, _session(&item->history()->session())
|
||||||
|
, _itemId(item->fullId())
|
||||||
|
, _timer([=] { update(); }) {
|
||||||
|
_session->sponsoredMessages().requestForVideo(item, crl::guard(this, [=](
|
||||||
|
Data::SponsoredForVideo data) {
|
||||||
|
if (data.list.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_data = std::move(data);
|
||||||
|
if (_data->state.initial()
|
||||||
|
|| (_data->state.itemIndex > _data->list.size())
|
||||||
|
|| (_data->state.itemIndex == _data->list.size()
|
||||||
|
&& _data->state.leftTillShow <= 0)) {
|
||||||
|
_data->state.itemIndex = 0;
|
||||||
|
_data->state.leftTillShow = std::max(
|
||||||
|
_data->startDelay,
|
||||||
|
kStartDelayMin);
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaybackSponsored::~PlaybackSponsored() {
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::start() {
|
||||||
|
_started = true;
|
||||||
|
if (!_paused) {
|
||||||
|
_start = crl::now();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::setPaused(bool paused) {
|
||||||
|
if (_paused == paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_paused = paused;
|
||||||
|
if (!_started) {
|
||||||
|
return;
|
||||||
|
} else if (_paused) {
|
||||||
|
update();
|
||||||
|
const auto state = computeState();
|
||||||
|
_start = 0;
|
||||||
|
_timer.cancel();
|
||||||
|
} else {
|
||||||
|
_start = crl::now();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::finish() {
|
||||||
|
_timer.cancel();
|
||||||
|
if (_data) {
|
||||||
|
saveState();
|
||||||
|
_data = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::update() {
|
||||||
|
if (!_data || !_start) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto [now, state] = computeState();
|
||||||
|
const auto message = (_data->state.itemIndex < _data->list.size())
|
||||||
|
? &_data->list[state.itemIndex]
|
||||||
|
: nullptr;
|
||||||
|
const auto duration = message
|
||||||
|
? std::max(
|
||||||
|
message->durationMin + kDurationMin,
|
||||||
|
message->durationMax)
|
||||||
|
: crl::time(0);
|
||||||
|
if (_data->state.leftTillShow > 0 && state.leftTillShow <= 0) {
|
||||||
|
_data->state.leftTillShow = 0;
|
||||||
|
if (duration) {
|
||||||
|
show(*message);
|
||||||
|
|
||||||
|
_start = now;
|
||||||
|
_timer.callOnce(duration);
|
||||||
|
saveState();
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
} else if (_data->state.leftTillShow <= 0
|
||||||
|
&& state.leftTillShow <= -duration) {
|
||||||
|
hide();
|
||||||
|
|
||||||
|
++_data->state.itemIndex;
|
||||||
|
_data->state.leftTillShow = std::max(
|
||||||
|
_data->betweenDelay,
|
||||||
|
kStartDelayMin);
|
||||||
|
_start = now;
|
||||||
|
_timer.callOnce(_data->state.leftTillShow);
|
||||||
|
saveState();
|
||||||
|
} else {
|
||||||
|
if (state.leftTillShow <= 0 && duration && !_widget) {
|
||||||
|
show(*message);
|
||||||
|
}
|
||||||
|
_data->state = state;
|
||||||
|
_timer.callOnce((state.leftTillShow > 0)
|
||||||
|
? state.leftTillShow
|
||||||
|
: (state.leftTillShow + duration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::show(const Data::SponsoredMessage &data) {
|
||||||
|
_widget = std::make_unique<Ui::RpWidget>(_parent);
|
||||||
|
_widget->setGeometry(_parent->rect());
|
||||||
|
_widget->paintRequest() | rpl::start_with_next([=] {
|
||||||
|
auto p = QPainter(_widget.get());
|
||||||
|
p.fillRect(_widget->rect(), QColor(0, 128, 0, 128));
|
||||||
|
}, _widget->lifetime());
|
||||||
|
_widget->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::hide() {
|
||||||
|
_widget = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::saveState() {
|
||||||
|
_session->sponsoredMessages().updateForVideo(
|
||||||
|
_itemId,
|
||||||
|
computeState().data);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaybackSponsored::State PlaybackSponsored::computeState() const {
|
||||||
|
auto result = State{ crl::now() };
|
||||||
|
if (!_data) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.data = _data->state;
|
||||||
|
if (!_start) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const auto elapsed = result.now - _start;
|
||||||
|
result.data.leftTillShow -= elapsed;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::lifetime &PlaybackSponsored::lifetime() {
|
||||||
|
return _lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlaybackSponsored::Has(HistoryItem *item) {
|
||||||
|
return item
|
||||||
|
&& item->history()->session().sponsoredMessages().canHaveFor(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Media::View
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/timer.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
|
#include "data/components/sponsored_messages.h"
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class Session;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Media::View {
|
||||||
|
|
||||||
|
class PlaybackSponsored final : public base::has_weak_ptr {
|
||||||
|
public:
|
||||||
|
PlaybackSponsored(QWidget *parent, not_null<HistoryItem*> item);
|
||||||
|
~PlaybackSponsored();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void setPaused(bool paused);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
||||||
|
[[nodiscard]] static bool Has(HistoryItem *item);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct State {
|
||||||
|
crl::time now = 0;
|
||||||
|
Data::SponsoredForVideoState data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void finish();
|
||||||
|
void show(const Data::SponsoredMessage &data);
|
||||||
|
void hide();
|
||||||
|
[[nodiscard]] State computeState() const;
|
||||||
|
void saveState();
|
||||||
|
|
||||||
|
const not_null<QWidget*> _parent;
|
||||||
|
const not_null<Main::Session*> _session;
|
||||||
|
const FullMsgId _itemId;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::RpWidget> _widget;
|
||||||
|
|
||||||
|
crl::time _start = 0;
|
||||||
|
bool _started = false;
|
||||||
|
bool _paused = false;
|
||||||
|
base::Timer _timer;
|
||||||
|
|
||||||
|
std::optional<Data::SponsoredForVideo> _data;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Media::View
|
Loading…
Add table
Reference in a new issue