mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-29 17:03:03 +02:00
Show sponsored messages in video.
This commit is contained in:
parent
f7e1b2c70c
commit
ecc955d2ce
12 changed files with 494 additions and 54 deletions
|
@ -682,7 +682,11 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
|
||||||
if (!entryPtr) {
|
if (!entryPtr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const auto &data = entryPtr->sponsored;
|
return lookupDetails(entryPtr->sponsored);
|
||||||
|
}
|
||||||
|
|
||||||
|
SponsoredMessages::Details SponsoredMessages::lookupDetails(
|
||||||
|
const SponsoredMessage &data) const {
|
||||||
return {
|
return {
|
||||||
.info = Prepare(data),
|
.info = Prepare(data),
|
||||||
.link = data.link,
|
.link = data.link,
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct SponsoredMessage {
|
||||||
QByteArray randomId;
|
QByteArray randomId;
|
||||||
SponsoredFrom from;
|
SponsoredFrom from;
|
||||||
TextWithEntities textWithEntities;
|
TextWithEntities textWithEntities;
|
||||||
History *history = nullptr;
|
not_null<History*> history;
|
||||||
QString link;
|
QString link;
|
||||||
TextWithEntities sponsorInfo;
|
TextWithEntities sponsorInfo;
|
||||||
TextWithEntities additionalInfo;
|
TextWithEntities additionalInfo;
|
||||||
|
@ -141,6 +141,7 @@ public:
|
||||||
SponsoredForVideoState state);
|
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(const SponsoredMessage &data) const;
|
||||||
[[nodiscard]] Details lookupDetails(
|
[[nodiscard]] Details lookupDetails(
|
||||||
const Api::SponsoredSearchResult &data) const;
|
const Api::SponsoredSearchResult &data) const;
|
||||||
void clicked(const FullMsgId &fullId, bool isMedia, bool isFullscreen);
|
void clicked(const FullMsgId &fullId, bool isMedia, bool isFullscreen);
|
||||||
|
|
|
@ -3251,16 +3251,13 @@ void InnerWidget::showSponsoredMenu(int peerSearchIndex, QPoint globalPos) {
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
Menu::FillSponsored(
|
Menu::FillSponsored(
|
||||||
this,
|
|
||||||
Ui::Menu::CreateAddActionCallback(_menu),
|
Ui::Menu::CreateAddActionCallback(_menu),
|
||||||
_controller->uiShow(),
|
_controller->uiShow(),
|
||||||
Menu::SponsoredPhrases::Search,
|
Menu::SponsoredPhrases::Search,
|
||||||
session().sponsoredMessages().lookupDetails(entry->sponsored->data),
|
session().sponsoredMessages().lookupDetails(entry->sponsored->data),
|
||||||
session().sponsoredMessages().createReportCallback(
|
session().sponsoredMessages().createReportCallback(
|
||||||
entry->sponsored->data.randomId,
|
entry->sponsored->data.randomId,
|
||||||
remove),
|
remove));
|
||||||
false,
|
|
||||||
false);
|
|
||||||
QObject::connect(_menu.get(), &QObject::destroyed, [=] {
|
QObject::connect(_menu.get(), &QObject::destroyed, [=] {
|
||||||
if (_peerSearchMenu >= 0
|
if (_peerSearchMenu >= 0
|
||||||
&& _peerSearchMenu < _peerSearchResults.size()) {
|
&& _peerSearchMenu < _peerSearchResults.size()) {
|
||||||
|
|
|
@ -2880,11 +2880,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (sponsored) {
|
if (sponsored) {
|
||||||
Menu::FillSponsored(
|
Menu::FillSponsored(
|
||||||
this,
|
|
||||||
Ui::Menu::CreateAddActionCallback(_menu),
|
Ui::Menu::CreateAddActionCallback(_menu),
|
||||||
controller->uiShow(),
|
controller->uiShow(),
|
||||||
sponsored->fullId(),
|
sponsored->fullId());
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
if (isUponSelected > 0) {
|
if (isUponSelected > 0) {
|
||||||
addReplyAction(item);
|
addReplyAction(item);
|
||||||
|
|
|
@ -1086,3 +1086,34 @@ mediaviewSponsoredButton: RoundButton(defaultActiveButton) {
|
||||||
|
|
||||||
ripple: universalRippleAnimation;
|
ripple: universalRippleAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaSponsoredSkip: 16px;
|
||||||
|
mediaSponsoredShift: 16px;
|
||||||
|
mediaSponsoredPadding: margins(12px, 8px, 8px, 8px);
|
||||||
|
mediaSponsoredThumb: 48px;
|
||||||
|
mediaSponsoredClose: IconButton(mediaviewControlsButton) {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
rippleAreaSize: 40px;
|
||||||
|
rippleAreaPosition: point(12px, 12px);
|
||||||
|
|
||||||
|
icon: icon {{ "box_button_close", mediaviewPlaybackIconFg }};
|
||||||
|
iconOver: icon {{ "box_button_close", mediaviewPlaybackIconFgOver }};
|
||||||
|
iconPosition: point(24px, 24px);
|
||||||
|
}
|
||||||
|
mediaSponsoredAbout: RoundButton(defaultActiveButton) {
|
||||||
|
textFg: windowActiveTextFg;
|
||||||
|
textFgOver: windowActiveTextFg;
|
||||||
|
textBg: lightButtonBgOver;
|
||||||
|
textBgOver: lightButtonBgOver;
|
||||||
|
width: -12px;
|
||||||
|
height: 18px;
|
||||||
|
radius: 9px;
|
||||||
|
textTop: 0px;
|
||||||
|
style: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(12px);
|
||||||
|
}
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: lightButtonBgRipple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1610,7 +1610,11 @@ void OverlayWidget::fillContextMenuActions(
|
||||||
if (const auto window = findWindow()) {
|
if (const auto window = findWindow()) {
|
||||||
const auto show = window->uiShow();
|
const auto show = window->uiShow();
|
||||||
const auto fullId = _message->fullId();
|
const auto fullId = _message->fullId();
|
||||||
Menu::FillSponsored(_body, addAction, show, fullId, true);
|
Menu::FillSponsored(
|
||||||
|
addAction,
|
||||||
|
show,
|
||||||
|
fullId,
|
||||||
|
{ .dark = true, .skipInfo = true });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4129,7 +4133,10 @@ bool OverlayWidget::createStreamingObjects() {
|
||||||
static_cast<PlaybackControls::Delegate*>(this));
|
static_cast<PlaybackControls::Delegate*>(this));
|
||||||
_streamed->controls->show();
|
_streamed->controls->show();
|
||||||
_streamed->sponsored = PlaybackSponsored::Has(_message)
|
_streamed->sponsored = PlaybackSponsored::Has(_message)
|
||||||
? std::make_unique<PlaybackSponsored>(_body, _message)
|
? std::make_unique<PlaybackSponsored>(
|
||||||
|
_streamed->controls.get(),
|
||||||
|
uiShow(),
|
||||||
|
_message)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (const auto sponsored = _streamed->sponsored.get()) {
|
if (const auto sponsored = _streamed->sponsored.get()) {
|
||||||
_layerBg->layerShownValue(
|
_layerBg->layerShownValue(
|
||||||
|
|
|
@ -8,10 +8,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/view/media_view_playback_sponsored.h"
|
#include "media/view/media_view_playback_sponsored.h"
|
||||||
|
|
||||||
#include "data/components/sponsored_messages.h"
|
#include "data/components/sponsored_messages.h"
|
||||||
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "menu/menu_sponsored.h"
|
||||||
|
#include "ui/widgets/menu/menu_add_action_callback.h"
|
||||||
|
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/basic_click_handlers.h"
|
||||||
|
#include "ui/ui_utility.h"
|
||||||
|
#include "ui/cached_round_corners.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_media_view.h"
|
||||||
|
|
||||||
namespace Media::View {
|
namespace Media::View {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -19,14 +33,341 @@ namespace {
|
||||||
constexpr auto kStartDelayMin = crl::time(1000);
|
constexpr auto kStartDelayMin = crl::time(1000);
|
||||||
constexpr auto kDurationMin = 5 * crl::time(1000);
|
constexpr auto kDurationMin = 5 * crl::time(1000);
|
||||||
|
|
||||||
|
enum class Action {
|
||||||
|
Close,
|
||||||
|
PromotePremium,
|
||||||
|
Pause,
|
||||||
|
Unpause,
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] style::RoundButton PrepareAboutStyle() {
|
||||||
|
static auto textBg = style::complex_color([] {
|
||||||
|
auto result = st::mediaviewTextLinkFg->c;
|
||||||
|
result.setAlphaF(result.alphaF() * 0.1);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
static auto textBgOver = style::complex_color([] {
|
||||||
|
auto result = st::mediaviewTextLinkFg->c;
|
||||||
|
result.setAlphaF(result.alphaF() * 0.15);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
static auto rippleColor = style::complex_color([] {
|
||||||
|
auto result = st::mediaviewTextLinkFg->c;
|
||||||
|
result.setAlphaF(result.alphaF() * 0.2);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto result = st::mediaSponsoredAbout;
|
||||||
|
result.textFg = st::mediaviewTextLinkFg;
|
||||||
|
result.textFgOver = st::mediaviewTextLinkFg;
|
||||||
|
result.textBg = textBg.color();
|
||||||
|
result.textBgOver = textBgOver.color();
|
||||||
|
result.ripple.color = rippleColor.color();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PlaybackSponsored::PlaybackSponsored(
|
class PlaybackSponsored::Message final : public Ui::RpWidget {
|
||||||
|
public:
|
||||||
|
Message(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
const Data::SponsoredMessage &data);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<Action> actions() const;
|
||||||
|
|
||||||
|
void setFinalPosition(int x, int y);
|
||||||
|
|
||||||
|
void fadeIn();
|
||||||
|
void fadeOut(Fn<void()> hidden);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
|
||||||
|
void populate();
|
||||||
|
void startFadeIn();
|
||||||
|
void updateShown(Fn<void()> finished = nullptr);
|
||||||
|
|
||||||
|
const not_null<Main::Session*> _session;
|
||||||
|
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||||
|
const Data::SponsoredMessage _data;
|
||||||
|
|
||||||
|
style::RoundButton _aboutSt;
|
||||||
|
std::unique_ptr<Ui::RoundButton> _about;
|
||||||
|
std::unique_ptr<Ui::IconButton> _close;
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||||
|
rpl::event_stream<Action> _actions;
|
||||||
|
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _photo;
|
||||||
|
Ui::Text::String _title;
|
||||||
|
Ui::Text::String _text;
|
||||||
|
|
||||||
|
QPoint _finalPosition;
|
||||||
|
int _left = 0;
|
||||||
|
int _top = 0;
|
||||||
|
int _titleHeight = 0;
|
||||||
|
int _textHeight = 0;
|
||||||
|
|
||||||
|
QImage _cache;
|
||||||
|
Ui::Animations::Simple _showAnimation;
|
||||||
|
bool _shown = false;
|
||||||
|
bool _over = false;
|
||||||
|
bool _pressed = false;
|
||||||
|
|
||||||
|
rpl::lifetime _photoLifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
PlaybackSponsored::Message::Message(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
const Data::SponsoredMessage &data)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _session(&data.history->session())
|
||||||
|
, _show(std::move(show))
|
||||||
|
, _data(data)
|
||||||
|
, _aboutSt(PrepareAboutStyle())
|
||||||
|
, _about(std::make_unique<Ui::RoundButton>(
|
||||||
|
this,
|
||||||
|
tr::lng_search_sponsored_button(),
|
||||||
|
_aboutSt))
|
||||||
|
, _close(std::make_unique<Ui::IconButton>(this, st::mediaSponsoredClose)) {
|
||||||
|
_about->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||||
|
setMouseTracking(true);
|
||||||
|
populate();
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<Action> PlaybackSponsored::Message::actions() const {
|
||||||
|
return _actions.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::setFinalPosition(int x, int y) {
|
||||||
|
_finalPosition = { x, y };
|
||||||
|
if (_shown) {
|
||||||
|
updateShown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::fadeIn() {
|
||||||
|
_shown = true;
|
||||||
|
if (!_photo || _photo->loaded()) {
|
||||||
|
startFadeIn();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_photo->owner()->session().downloaderTaskFinished(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return _photo->loaded();
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
_photoLifetime.destroy();
|
||||||
|
startFadeIn();
|
||||||
|
}, _photoLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::startFadeIn() {
|
||||||
|
if (!_shown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_cache = Ui::GrabWidgetToImage(this);
|
||||||
|
_about->hide();
|
||||||
|
_close->hide();
|
||||||
|
_showAnimation.start([=] {
|
||||||
|
updateShown([=] {
|
||||||
|
_session->sponsoredMessages().view(_data.randomId);
|
||||||
|
});
|
||||||
|
}, 0., 1., st::fadeWrapDuration);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::fadeOut(Fn<void()> hidden) {
|
||||||
|
if (!_shown) {
|
||||||
|
if (const auto onstack = hidden) {
|
||||||
|
onstack();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_shown = false;
|
||||||
|
_showAnimation.start([=] {
|
||||||
|
updateShown(hidden);
|
||||||
|
}, 1., 0., st::fadeWrapDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::updateShown(Fn<void()> finished) {
|
||||||
|
const auto shown = _showAnimation.value(_shown ? 1. : 0.);
|
||||||
|
const auto shift = anim::interpolate(st::mediaSponsoredShift, 0, shown);
|
||||||
|
move(_finalPosition.x(), _finalPosition.y() + shift);
|
||||||
|
update();
|
||||||
|
if (!_showAnimation.animating()) {
|
||||||
|
_cache = QImage();
|
||||||
|
_close->show();
|
||||||
|
_about->show();
|
||||||
|
if (const auto onstack = finished) {
|
||||||
|
onstack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::paintEvent(QPaintEvent *e) {
|
||||||
|
auto p = QPainter(this);
|
||||||
|
|
||||||
|
const auto shown = _showAnimation.value(_shown ? 1. : 0.);
|
||||||
|
if (!_cache.isNull()) {
|
||||||
|
p.setOpacity(shown);
|
||||||
|
p.drawImage(0, 0, _cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::FillRoundRect(
|
||||||
|
p,
|
||||||
|
rect(),
|
||||||
|
st::mediaviewSaveMsgBg,
|
||||||
|
Ui::MediaviewSaveCorners);
|
||||||
|
|
||||||
|
const auto &padding = st::mediaSponsoredPadding;
|
||||||
|
if (_photo) {
|
||||||
|
if (const auto image = _photo->image(Data::PhotoSize::Large)) {
|
||||||
|
const auto size = st::mediaSponsoredThumb;
|
||||||
|
const auto x = padding.left();
|
||||||
|
const auto y = (height() - size) / 2;
|
||||||
|
p.drawPixmap(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
image->pixSingle(
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
{ .options = Images::Option::RoundCircle }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setPen(st::mediaviewControlFg);
|
||||||
|
|
||||||
|
_title.draw(p, {
|
||||||
|
.position = { _left, _top },
|
||||||
|
.availableWidth = _about->x() - _left,
|
||||||
|
.palette = &st::mediaviewTextPalette,
|
||||||
|
});
|
||||||
|
|
||||||
|
_text.draw(p, {
|
||||||
|
.position = { _left, _top + _titleHeight },
|
||||||
|
.availableWidth = _close->x() - _left,
|
||||||
|
.palette = &st::mediaviewTextPalette,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
const auto &padding = st::mediaSponsoredPadding;
|
||||||
|
const auto point = e->pos();
|
||||||
|
const auto about = _about->geometry();
|
||||||
|
const auto close = _close->geometry();
|
||||||
|
const auto over = !about.marginsAdded(padding).contains(point)
|
||||||
|
&& !close.marginsAdded(padding).contains(point);
|
||||||
|
if (_over != over) {
|
||||||
|
_over = over;
|
||||||
|
setCursor(_over ? style::cur_pointer : style::cur_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::mousePressEvent(QMouseEvent *e) {
|
||||||
|
if (_over) {
|
||||||
|
_pressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
if (base::take(_pressed) && _over) {
|
||||||
|
_session->sponsoredMessages().clicked(_data.randomId, false, false);
|
||||||
|
UrlClickHandler::Open(_data.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlaybackSponsored::Message::resizeGetHeight(int newWidth) {
|
||||||
|
const auto &padding = st::mediaSponsoredPadding;
|
||||||
|
const auto userpic = st::mediaSponsoredThumb;
|
||||||
|
const auto innerWidth = newWidth - _left - _close->width();
|
||||||
|
const auto titleWidth = innerWidth - _about->width() - padding.right();
|
||||||
|
_titleHeight = _title.countHeight(titleWidth);
|
||||||
|
_textHeight = _text.countHeight(innerWidth);
|
||||||
|
|
||||||
|
const auto use = std::max(_titleHeight + _textHeight, userpic);
|
||||||
|
|
||||||
|
const auto height = padding.top() + use + padding.bottom();
|
||||||
|
_left = padding.left() + (_photo ? (userpic + padding.left()) : 0);
|
||||||
|
_top = padding.top() + (use - _titleHeight - _textHeight) / 2;
|
||||||
|
|
||||||
|
_about->move(
|
||||||
|
_left + std::min(titleWidth, _title.maxWidth()) + padding.right(),
|
||||||
|
_top);
|
||||||
|
_close->move(
|
||||||
|
newWidth - _close->width(),
|
||||||
|
(height - _close->height()) / 2);
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::Message::populate() {
|
||||||
|
const auto &from = _data.from;
|
||||||
|
const auto photo = from.photoId
|
||||||
|
? _data.history->owner().photo(from.photoId).get()
|
||||||
|
: nullptr;
|
||||||
|
if (photo) {
|
||||||
|
_photo = photo->createMediaView();
|
||||||
|
photo->load({}, LoadFromCloudOrLocal, true);
|
||||||
|
}
|
||||||
|
_title = Ui::Text::String(
|
||||||
|
st::semiboldTextStyle,
|
||||||
|
from.title,
|
||||||
|
kDefaultTextOptions,
|
||||||
|
st::msgMinWidth);
|
||||||
|
_text = Ui::Text::String(
|
||||||
|
st::defaultTextStyle,
|
||||||
|
_data.textWithEntities,
|
||||||
|
kMarkupTextOptions,
|
||||||
|
st::msgMinWidth);
|
||||||
|
|
||||||
|
_about->setClickedCallback([=] {
|
||||||
|
_menu = nullptr;
|
||||||
|
const auto parent = parentWidget();
|
||||||
|
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||||
|
parent,
|
||||||
|
st::mediaviewPopupMenu);
|
||||||
|
const auto raw = _menu.get();
|
||||||
|
const auto addAction = Ui::Menu::CreateAddActionCallback(raw);
|
||||||
|
Menu::FillSponsored(
|
||||||
|
addAction,
|
||||||
|
_show,
|
||||||
|
Menu::SponsoredPhrases::Channel,
|
||||||
|
_session->sponsoredMessages().lookupDetails(_data),
|
||||||
|
_session->sponsoredMessages().createReportCallback(
|
||||||
|
_data.randomId,
|
||||||
|
crl::guard(this, [=] { _actions.fire(Action::Close); })),
|
||||||
|
{ .dark = true });
|
||||||
|
_actions.fire(Action::Pause);
|
||||||
|
Ui::Connect(raw, &QObject::destroyed, this, [=] {
|
||||||
|
_actions.fire(Action::Unpause);
|
||||||
|
});
|
||||||
|
raw->popup(QCursor::pos());
|
||||||
|
});
|
||||||
|
_close->setClickedCallback([=] {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaybackSponsored::PlaybackSponsored(
|
||||||
|
not_null<Ui::RpWidget*> controls,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
not_null<HistoryItem*> item)
|
not_null<HistoryItem*> item)
|
||||||
: _parent(parent)
|
: _parent(controls->parentWidget())
|
||||||
, _session(&item->history()->session())
|
, _session(&item->history()->session())
|
||||||
|
, _show(std::move(show))
|
||||||
, _itemId(item->fullId())
|
, _itemId(item->fullId())
|
||||||
|
, _controlsGeometry(controls->geometryValue())
|
||||||
, _timer([=] { update(); }) {
|
, _timer([=] { update(); }) {
|
||||||
_session->sponsoredMessages().requestForVideo(item, crl::guard(this, [=](
|
_session->sponsoredMessages().requestForVideo(item, crl::guard(this, [=](
|
||||||
Data::SponsoredForVideo data) {
|
Data::SponsoredForVideo data) {
|
||||||
|
@ -60,6 +401,11 @@ void PlaybackSponsored::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackSponsored::setPaused(bool paused) {
|
void PlaybackSponsored::setPaused(bool paused) {
|
||||||
|
setPausedOutside(paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::updatePaused() {
|
||||||
|
const auto paused = _pausedInside || _pausedOutside;
|
||||||
if (_paused == paused) {
|
if (_paused == paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +423,22 @@ void PlaybackSponsored::setPaused(bool paused) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::setPausedInside(bool paused) {
|
||||||
|
if (_pausedInside == paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pausedInside = paused;
|
||||||
|
updatePaused();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaybackSponsored::setPausedOutside(bool paused) {
|
||||||
|
if (_pausedOutside == paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pausedOutside = paused;
|
||||||
|
updatePaused();
|
||||||
|
}
|
||||||
|
|
||||||
void PlaybackSponsored::finish() {
|
void PlaybackSponsored::finish() {
|
||||||
_timer.cancel();
|
_timer.cancel();
|
||||||
if (_data) {
|
if (_data) {
|
||||||
|
@ -132,18 +494,36 @@ void PlaybackSponsored::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PlaybackSponsored::show(const Data::SponsoredMessage &data) {
|
void PlaybackSponsored::show(const Data::SponsoredMessage &data) {
|
||||||
_widget = std::make_unique<Ui::RpWidget>(_parent);
|
_widget = std::make_unique<Message>(_parent, _show, data);
|
||||||
_widget->setGeometry(_parent->rect());
|
const auto raw = _widget.get();
|
||||||
_widget->paintRequest() | rpl::start_with_next([=] {
|
|
||||||
auto p = QPainter(_widget.get());
|
_controlsGeometry.value() | rpl::start_with_next([=](QRect controls) {
|
||||||
p.fillRect(_widget->rect(), QColor(0, 128, 0, 128));
|
raw->resizeToWidth(controls.width());
|
||||||
}, _widget->lifetime());
|
raw->setFinalPosition(
|
||||||
_widget->show();
|
controls.x(),
|
||||||
|
controls.y() - st::mediaSponsoredSkip - raw->height());
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
raw->actions() | rpl::start_with_next([=](Action action) {
|
||||||
|
switch (action) {
|
||||||
|
case Action::Close: hide(); break;
|
||||||
|
case Action::PromotePremium: break;
|
||||||
|
case Action::Pause: setPausedInside(true); break;
|
||||||
|
case Action::Unpause: setPausedInside(false); break;
|
||||||
|
}
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
raw->fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackSponsored::hide() {
|
void PlaybackSponsored::hide() {
|
||||||
_widget = nullptr;
|
_widget->fadeOut([this, raw = _widget.get()] {
|
||||||
|
if (_widget.get() == raw) {
|
||||||
|
_widget = nullptr;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackSponsored::saveState() {
|
void PlaybackSponsored::saveState() {
|
||||||
|
|
|
@ -11,15 +11,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/weak_ptr.h"
|
#include "base/weak_ptr.h"
|
||||||
#include "data/components/sponsored_messages.h"
|
#include "data/components/sponsored_messages.h"
|
||||||
|
|
||||||
|
namespace ChatHelpers {
|
||||||
|
class Show;
|
||||||
|
} // namespace ChatHelpers
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class RpWidget;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Media::View {
|
namespace Media::View {
|
||||||
|
|
||||||
class PlaybackSponsored final : public base::has_weak_ptr {
|
class PlaybackSponsored final : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
PlaybackSponsored(QWidget *parent, not_null<HistoryItem*> item);
|
PlaybackSponsored(
|
||||||
|
not_null<Ui::RpWidget*> controls,
|
||||||
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
|
not_null<HistoryItem*> item);
|
||||||
~PlaybackSponsored();
|
~PlaybackSponsored();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
@ -30,6 +41,7 @@ public:
|
||||||
[[nodiscard]] static bool Has(HistoryItem *item);
|
[[nodiscard]] static bool Has(HistoryItem *item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class Message;
|
||||||
struct State {
|
struct State {
|
||||||
crl::time now = 0;
|
crl::time now = 0;
|
||||||
Data::SponsoredForVideoState data;
|
Data::SponsoredForVideoState data;
|
||||||
|
@ -37,6 +49,9 @@ private:
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void finish();
|
void finish();
|
||||||
|
void updatePaused();
|
||||||
|
void setPausedInside(bool paused);
|
||||||
|
void setPausedOutside(bool paused);
|
||||||
void show(const Data::SponsoredMessage &data);
|
void show(const Data::SponsoredMessage &data);
|
||||||
void hide();
|
void hide();
|
||||||
[[nodiscard]] State computeState() const;
|
[[nodiscard]] State computeState() const;
|
||||||
|
@ -44,13 +59,17 @@ private:
|
||||||
|
|
||||||
const not_null<QWidget*> _parent;
|
const not_null<QWidget*> _parent;
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||||
const FullMsgId _itemId;
|
const FullMsgId _itemId;
|
||||||
|
|
||||||
std::unique_ptr<Ui::RpWidget> _widget;
|
rpl::variable<QRect> _controlsGeometry;
|
||||||
|
std::unique_ptr<Message> _widget;
|
||||||
|
|
||||||
crl::time _start = 0;
|
crl::time _start = 0;
|
||||||
bool _started = false;
|
bool _started = false;
|
||||||
bool _paused = false;
|
bool _paused = false;
|
||||||
|
bool _pausedInside = false;
|
||||||
|
bool _pausedOutside = false;
|
||||||
base::Timer _timer;
|
base::Timer _timer;
|
||||||
|
|
||||||
std::optional<Data::SponsoredForVideo> _data;
|
std::optional<Data::SponsoredForVideo> _data;
|
||||||
|
|
|
@ -287,14 +287,12 @@ void AboutBox(
|
||||||
top->setForceRippled(false);
|
top->setForceRippled(false);
|
||||||
});
|
});
|
||||||
FillSponsored(
|
FillSponsored(
|
||||||
top,
|
|
||||||
Ui::Menu::CreateAddActionCallback(menu->get()),
|
Ui::Menu::CreateAddActionCallback(menu->get()),
|
||||||
show,
|
show,
|
||||||
phrases,
|
phrases,
|
||||||
details,
|
details,
|
||||||
report,
|
report,
|
||||||
false,
|
{ .skipAbout = true });
|
||||||
true);
|
|
||||||
const auto global = top->mapToGlobal(
|
const auto global = top->mapToGlobal(
|
||||||
QPoint(top->width() / 4 * 3, top->height() / 2));
|
QPoint(top->width() / 4 * 3, top->height() / 2));
|
||||||
raw->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
|
raw->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
|
||||||
|
@ -390,18 +388,17 @@ void ShowReportSponsoredBox(
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void FillSponsored(
|
void FillSponsored(
|
||||||
not_null<Ui::RpWidget*> parent,
|
|
||||||
const Ui::Menu::MenuCallback &addAction,
|
const Ui::Menu::MenuCallback &addAction,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
SponsoredPhrases phrases,
|
SponsoredPhrases phrases,
|
||||||
const Data::SponsoredMessages::Details &details,
|
const Data::SponsoredMessages::Details &details,
|
||||||
Data::SponsoredReportAction report,
|
Data::SponsoredReportAction report,
|
||||||
bool mediaViewer,
|
SponsoredMenuSettings settings) {
|
||||||
bool skipAbout) {
|
|
||||||
const auto session = &show->session();
|
const auto session = &show->session();
|
||||||
const auto &info = details.info;
|
const auto &info = details.info;
|
||||||
|
const auto dark = settings.dark;
|
||||||
|
|
||||||
if (!mediaViewer && !info.empty()) {
|
if (!settings.skipInfo && !info.empty()) {
|
||||||
auto fillSubmenu = [&](not_null<Ui::PopupMenu*> menu) {
|
auto fillSubmenu = [&](not_null<Ui::PopupMenu*> menu) {
|
||||||
const auto allText = ranges::accumulate(
|
const auto allText = ranges::accumulate(
|
||||||
info,
|
info,
|
||||||
|
@ -416,8 +413,10 @@ void FillSponsored(
|
||||||
for (const auto &i : info) {
|
for (const auto &i : info) {
|
||||||
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
|
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
|
||||||
menu,
|
menu,
|
||||||
st::defaultMenu,
|
dark ? st::storiesMenu : st::defaultMenu,
|
||||||
st::historySponsorInfoItem,
|
(dark
|
||||||
|
? st::historySponsorInfoItemDark
|
||||||
|
: st::historySponsorInfoItem),
|
||||||
st::historyHasCustomEmojiPosition,
|
st::historyHasCustomEmojiPosition,
|
||||||
base::duplicate(i));
|
base::duplicate(i));
|
||||||
item->clicks(
|
item->clicks(
|
||||||
|
@ -431,27 +430,31 @@ void FillSponsored(
|
||||||
addAction({
|
addAction({
|
||||||
.text = tr::lng_sponsored_info_menu(tr::now),
|
.text = tr::lng_sponsored_info_menu(tr::now),
|
||||||
.handler = nullptr,
|
.handler = nullptr,
|
||||||
.icon = &st::menuIconChannel,
|
.icon = (dark
|
||||||
|
? &st::mediaMenuIconChannel
|
||||||
|
: &st::menuIconChannel),
|
||||||
.fillSubmenu = std::move(fillSubmenu),
|
.fillSubmenu = std::move(fillSubmenu),
|
||||||
});
|
});
|
||||||
addAction({
|
addAction({
|
||||||
.separatorSt = &st::expandedMenuSeparator,
|
.separatorSt = (dark
|
||||||
|
? &st::mediaviewMenuSeparator
|
||||||
|
: &st::expandedMenuSeparator),
|
||||||
.isSeparator = true,
|
.isSeparator = true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (details.canReport) {
|
if (details.canReport) {
|
||||||
if (!skipAbout) {
|
if (!settings.skipAbout) {
|
||||||
addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
|
addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
|
||||||
show->show(Box(AboutBox, show, phrases, details, report));
|
show->show(Box(AboutBox, show, phrases, details, report));
|
||||||
}, (mediaViewer ? &st::mediaMenuIconInfo : &st::menuIconInfo));
|
}, (dark ? &st::mediaMenuIconInfo : &st::menuIconInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
|
addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
|
||||||
ShowReportSponsoredBox(show, report);
|
ShowReportSponsoredBox(show, report);
|
||||||
}, (mediaViewer ? &st::mediaMenuIconBlock : &st::menuIconBlock));
|
}, (dark ? &st::mediaMenuIconBlock : &st::menuIconBlock));
|
||||||
|
|
||||||
addAction({
|
addAction({
|
||||||
.separatorSt = (mediaViewer
|
.separatorSt = (dark
|
||||||
? &st::mediaviewMenuSeparator
|
? &st::mediaviewMenuSeparator
|
||||||
: &st::expandedMenuSeparator),
|
: &st::expandedMenuSeparator),
|
||||||
.isSeparator = true,
|
.isSeparator = true,
|
||||||
|
@ -464,26 +467,22 @@ void FillSponsored(
|
||||||
} else {
|
} else {
|
||||||
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
|
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
|
||||||
}
|
}
|
||||||
}, (mediaViewer ? &st::mediaMenuIconCancel : &st::menuIconCancel));
|
}, (dark ? &st::mediaMenuIconCancel : &st::menuIconCancel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillSponsored(
|
void FillSponsored(
|
||||||
not_null<Ui::RpWidget*> parent,
|
|
||||||
const Ui::Menu::MenuCallback &addAction,
|
const Ui::Menu::MenuCallback &addAction,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
const FullMsgId &fullId,
|
const FullMsgId &fullId,
|
||||||
bool mediaViewer,
|
SponsoredMenuSettings settings) {
|
||||||
bool skipAbout) {
|
|
||||||
const auto session = &show->session();
|
const auto session = &show->session();
|
||||||
FillSponsored(
|
FillSponsored(
|
||||||
parent,
|
|
||||||
addAction,
|
addAction,
|
||||||
show,
|
show,
|
||||||
PhrasesForMessage(fullId),
|
PhrasesForMessage(fullId),
|
||||||
session->sponsoredMessages().lookupDetails(fullId),
|
session->sponsoredMessages().lookupDetails(fullId),
|
||||||
session->sponsoredMessages().createReportCallback(fullId),
|
session->sponsoredMessages().createReportCallback(fullId),
|
||||||
mediaViewer,
|
settings);
|
||||||
skipAbout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowSponsored(
|
void ShowSponsored(
|
||||||
|
@ -495,11 +494,9 @@ void ShowSponsored(
|
||||||
st::popupMenuWithIcons);
|
st::popupMenuWithIcons);
|
||||||
|
|
||||||
FillSponsored(
|
FillSponsored(
|
||||||
parent,
|
|
||||||
Ui::Menu::CreateAddActionCallback(menu),
|
Ui::Menu::CreateAddActionCallback(menu),
|
||||||
show,
|
show,
|
||||||
fullId,
|
fullId);
|
||||||
false);
|
|
||||||
|
|
||||||
menu->popup(QCursor::pos());
|
menu->popup(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,23 +33,25 @@ enum class SponsoredPhrases {
|
||||||
Search,
|
Search,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SponsoredMenuSettings {
|
||||||
|
bool dark = false;
|
||||||
|
bool skipAbout = false;
|
||||||
|
bool skipInfo = false;
|
||||||
|
};
|
||||||
|
|
||||||
void FillSponsored(
|
void FillSponsored(
|
||||||
not_null<Ui::RpWidget*> parent,
|
|
||||||
const Ui::Menu::MenuCallback &addAction,
|
const Ui::Menu::MenuCallback &addAction,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
SponsoredPhrases phrases,
|
SponsoredPhrases phrases,
|
||||||
const Data::SponsoredMessageDetails &details,
|
const Data::SponsoredMessageDetails &details,
|
||||||
Data::SponsoredReportAction report,
|
Data::SponsoredReportAction report,
|
||||||
bool mediaViewer,
|
SponsoredMenuSettings settings = {});
|
||||||
bool skipAbout);
|
|
||||||
|
|
||||||
void FillSponsored(
|
void FillSponsored(
|
||||||
not_null<Ui::RpWidget*> parent,
|
|
||||||
const Ui::Menu::MenuCallback &addAction,
|
const Ui::Menu::MenuCallback &addAction,
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
const FullMsgId &fullId,
|
const FullMsgId &fullId,
|
||||||
bool mediaViewer,
|
SponsoredMenuSettings settings = {});
|
||||||
bool skipAbout = false);
|
|
||||||
|
|
||||||
void ShowSponsored(
|
void ShowSponsored(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
|
|
|
@ -947,6 +947,9 @@ historySponsorInfoItem: FlatLabel(defaultFlatLabel) {
|
||||||
minWidth: 136px;
|
minWidth: 136px;
|
||||||
maxHeight: 120px;
|
maxHeight: 120px;
|
||||||
}
|
}
|
||||||
|
historySponsorInfoItemDark: FlatLabel(historySponsorInfoItem) {
|
||||||
|
textFg: mediaviewControlFg;
|
||||||
|
}
|
||||||
historyHasCustomEmoji: FlatLabel(defaultFlatLabel) {
|
historyHasCustomEmoji: FlatLabel(defaultFlatLabel) {
|
||||||
style: TextStyle(defaultTextStyle) {
|
style: TextStyle(defaultTextStyle) {
|
||||||
font: font(11px);
|
font: font(11px);
|
||||||
|
|
|
@ -204,6 +204,7 @@ menuBlueIconGroupCreate: icon {{ "menu/groups_create", lightButtonFg }};
|
||||||
|
|
||||||
mediaMenuIconStickers: icon {{ "menu/stickers", mediaviewMenuFg }};
|
mediaMenuIconStickers: icon {{ "menu/stickers", mediaviewMenuFg }};
|
||||||
mediaMenuIconCancel: icon {{ "menu/cancel", mediaviewMenuFg }};
|
mediaMenuIconCancel: icon {{ "menu/cancel", mediaviewMenuFg }};
|
||||||
|
mediaMenuIconChannel: icon {{ "menu/channel", mediaviewMenuFg }};
|
||||||
mediaMenuIconShowInChat: icon {{ "menu/show_in_chat", mediaviewMenuFg }};
|
mediaMenuIconShowInChat: icon {{ "menu/show_in_chat", mediaviewMenuFg }};
|
||||||
mediaMenuIconShowInFolder: icon {{ "menu/show_in_folder", mediaviewMenuFg }};
|
mediaMenuIconShowInFolder: icon {{ "menu/show_in_folder", mediaviewMenuFg }};
|
||||||
mediaMenuIconDownload: icon {{ "menu/download", mediaviewMenuFg }};
|
mediaMenuIconDownload: icon {{ "menu/download", mediaviewMenuFg }};
|
||||||
|
|
Loading…
Add table
Reference in a new issue