Show sponsored messages in video.

This commit is contained in:
John Preston 2025-07-11 13:23:49 +04:00
parent f7e1b2c70c
commit ecc955d2ce
12 changed files with 494 additions and 54 deletions

View file

@ -682,7 +682,11 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
if (!entryPtr) {
return {};
}
const auto &data = entryPtr->sponsored;
return lookupDetails(entryPtr->sponsored);
}
SponsoredMessages::Details SponsoredMessages::lookupDetails(
const SponsoredMessage &data) const {
return {
.info = Prepare(data),
.link = data.link,

View file

@ -67,7 +67,7 @@ struct SponsoredMessage {
QByteArray randomId;
SponsoredFrom from;
TextWithEntities textWithEntities;
History *history = nullptr;
not_null<History*> history;
QString link;
TextWithEntities sponsorInfo;
TextWithEntities additionalInfo;
@ -141,6 +141,7 @@ public:
SponsoredForVideoState state);
void clearItems(not_null<History*> history);
[[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const;
[[nodiscard]] Details lookupDetails(const SponsoredMessage &data) const;
[[nodiscard]] Details lookupDetails(
const Api::SponsoredSearchResult &data) const;
void clicked(const FullMsgId &fullId, bool isMedia, bool isFullscreen);

View file

@ -3251,16 +3251,13 @@ void InnerWidget::showSponsoredMenu(int peerSearchIndex, QPoint globalPos) {
refresh();
});
Menu::FillSponsored(
this,
Ui::Menu::CreateAddActionCallback(_menu),
_controller->uiShow(),
Menu::SponsoredPhrases::Search,
session().sponsoredMessages().lookupDetails(entry->sponsored->data),
session().sponsoredMessages().createReportCallback(
entry->sponsored->data.randomId,
remove),
false,
false);
remove));
QObject::connect(_menu.get(), &QObject::destroyed, [=] {
if (_peerSearchMenu >= 0
&& _peerSearchMenu < _peerSearchResults.size()) {

View file

@ -2880,11 +2880,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
: nullptr;
if (sponsored) {
Menu::FillSponsored(
this,
Ui::Menu::CreateAddActionCallback(_menu),
controller->uiShow(),
sponsored->fullId(),
false);
sponsored->fullId());
}
if (isUponSelected > 0) {
addReplyAction(item);

View file

@ -1086,3 +1086,34 @@ mediaviewSponsoredButton: RoundButton(defaultActiveButton) {
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;
}
}

View file

@ -1610,7 +1610,11 @@ void OverlayWidget::fillContextMenuActions(
if (const auto window = findWindow()) {
const auto show = window->uiShow();
const auto fullId = _message->fullId();
Menu::FillSponsored(_body, addAction, show, fullId, true);
Menu::FillSponsored(
addAction,
show,
fullId,
{ .dark = true, .skipInfo = true });
}
return;
}
@ -4129,7 +4133,10 @@ bool OverlayWidget::createStreamingObjects() {
static_cast<PlaybackControls::Delegate*>(this));
_streamed->controls->show();
_streamed->sponsored = PlaybackSponsored::Has(_message)
? std::make_unique<PlaybackSponsored>(_body, _message)
? std::make_unique<PlaybackSponsored>(
_streamed->controls.get(),
uiShow(),
_message)
: nullptr;
if (const auto sponsored = _streamed->sponsored.get()) {
_layerBg->layerShownValue(

View file

@ -8,10 +8,24 @@ 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_file_origin.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.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 {
@ -19,14 +33,341 @@ namespace {
constexpr auto kStartDelayMin = 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
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,
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)
: _parent(parent)
: _parent(controls->parentWidget())
, _session(&item->history()->session())
, _show(std::move(show))
, _itemId(item->fullId())
, _controlsGeometry(controls->geometryValue())
, _timer([=] { update(); }) {
_session->sponsoredMessages().requestForVideo(item, crl::guard(this, [=](
Data::SponsoredForVideo data) {
@ -60,6 +401,11 @@ void PlaybackSponsored::start() {
}
void PlaybackSponsored::setPaused(bool paused) {
setPausedOutside(paused);
}
void PlaybackSponsored::updatePaused() {
const auto paused = _pausedInside || _pausedOutside;
if (_paused == paused) {
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() {
_timer.cancel();
if (_data) {
@ -132,18 +494,36 @@ void PlaybackSponsored::update() {
}
}
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();
_widget = std::make_unique<Message>(_parent, _show, data);
const auto raw = _widget.get();
_controlsGeometry.value() | rpl::start_with_next([=](QRect controls) {
raw->resizeToWidth(controls.width());
raw->setFinalPosition(
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() {
_widget = nullptr;
_widget->fadeOut([this, raw = _widget.get()] {
if (_widget.get() == raw) {
_widget = nullptr;
}
});
}
void PlaybackSponsored::saveState() {

View file

@ -11,15 +11,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/weak_ptr.h"
#include "data/components/sponsored_messages.h"
namespace ChatHelpers {
class Show;
} // namespace ChatHelpers
namespace Main {
class Session;
} // namespace Main
namespace Ui {
class RpWidget;
} // namespace Ui
namespace Media::View {
class PlaybackSponsored final : public base::has_weak_ptr {
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();
void start();
@ -30,6 +41,7 @@ public:
[[nodiscard]] static bool Has(HistoryItem *item);
private:
class Message;
struct State {
crl::time now = 0;
Data::SponsoredForVideoState data;
@ -37,6 +49,9 @@ private:
void update();
void finish();
void updatePaused();
void setPausedInside(bool paused);
void setPausedOutside(bool paused);
void show(const Data::SponsoredMessage &data);
void hide();
[[nodiscard]] State computeState() const;
@ -44,13 +59,17 @@ private:
const not_null<QWidget*> _parent;
const not_null<Main::Session*> _session;
const std::shared_ptr<ChatHelpers::Show> _show;
const FullMsgId _itemId;
std::unique_ptr<Ui::RpWidget> _widget;
rpl::variable<QRect> _controlsGeometry;
std::unique_ptr<Message> _widget;
crl::time _start = 0;
bool _started = false;
bool _paused = false;
bool _pausedInside = false;
bool _pausedOutside = false;
base::Timer _timer;
std::optional<Data::SponsoredForVideo> _data;

View file

@ -287,14 +287,12 @@ void AboutBox(
top->setForceRippled(false);
});
FillSponsored(
top,
Ui::Menu::CreateAddActionCallback(menu->get()),
show,
phrases,
details,
report,
false,
true);
{ .skipAbout = true });
const auto global = top->mapToGlobal(
QPoint(top->width() / 4 * 3, top->height() / 2));
raw->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
@ -390,18 +388,17 @@ void ShowReportSponsoredBox(
} // namespace
void FillSponsored(
not_null<Ui::RpWidget*> parent,
const Ui::Menu::MenuCallback &addAction,
std::shared_ptr<ChatHelpers::Show> show,
SponsoredPhrases phrases,
const Data::SponsoredMessages::Details &details,
Data::SponsoredReportAction report,
bool mediaViewer,
bool skipAbout) {
SponsoredMenuSettings settings) {
const auto session = &show->session();
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) {
const auto allText = ranges::accumulate(
info,
@ -416,8 +413,10 @@ void FillSponsored(
for (const auto &i : info) {
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
menu,
st::defaultMenu,
st::historySponsorInfoItem,
dark ? st::storiesMenu : st::defaultMenu,
(dark
? st::historySponsorInfoItemDark
: st::historySponsorInfoItem),
st::historyHasCustomEmojiPosition,
base::duplicate(i));
item->clicks(
@ -431,27 +430,31 @@ void FillSponsored(
addAction({
.text = tr::lng_sponsored_info_menu(tr::now),
.handler = nullptr,
.icon = &st::menuIconChannel,
.icon = (dark
? &st::mediaMenuIconChannel
: &st::menuIconChannel),
.fillSubmenu = std::move(fillSubmenu),
});
addAction({
.separatorSt = &st::expandedMenuSeparator,
.separatorSt = (dark
? &st::mediaviewMenuSeparator
: &st::expandedMenuSeparator),
.isSeparator = true,
});
}
if (details.canReport) {
if (!skipAbout) {
if (!settings.skipAbout) {
addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
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), [=] {
ShowReportSponsoredBox(show, report);
}, (mediaViewer ? &st::mediaMenuIconBlock : &st::menuIconBlock));
}, (dark ? &st::mediaMenuIconBlock : &st::menuIconBlock));
addAction({
.separatorSt = (mediaViewer
.separatorSt = (dark
? &st::mediaviewMenuSeparator
: &st::expandedMenuSeparator),
.isSeparator = true,
@ -464,26 +467,22 @@ void FillSponsored(
} else {
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
}
}, (mediaViewer ? &st::mediaMenuIconCancel : &st::menuIconCancel));
}, (dark ? &st::mediaMenuIconCancel : &st::menuIconCancel));
}
void FillSponsored(
not_null<Ui::RpWidget*> parent,
const Ui::Menu::MenuCallback &addAction,
std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId,
bool mediaViewer,
bool skipAbout) {
SponsoredMenuSettings settings) {
const auto session = &show->session();
FillSponsored(
parent,
addAction,
show,
PhrasesForMessage(fullId),
session->sponsoredMessages().lookupDetails(fullId),
session->sponsoredMessages().createReportCallback(fullId),
mediaViewer,
skipAbout);
settings);
}
void ShowSponsored(
@ -495,11 +494,9 @@ void ShowSponsored(
st::popupMenuWithIcons);
FillSponsored(
parent,
Ui::Menu::CreateAddActionCallback(menu),
show,
fullId,
false);
fullId);
menu->popup(QCursor::pos());
}

View file

@ -33,23 +33,25 @@ enum class SponsoredPhrases {
Search,
};
struct SponsoredMenuSettings {
bool dark = false;
bool skipAbout = false;
bool skipInfo = false;
};
void FillSponsored(
not_null<Ui::RpWidget*> parent,
const Ui::Menu::MenuCallback &addAction,
std::shared_ptr<ChatHelpers::Show> show,
SponsoredPhrases phrases,
const Data::SponsoredMessageDetails &details,
Data::SponsoredReportAction report,
bool mediaViewer,
bool skipAbout);
SponsoredMenuSettings settings = {});
void FillSponsored(
not_null<Ui::RpWidget*> parent,
const Ui::Menu::MenuCallback &addAction,
std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId,
bool mediaViewer,
bool skipAbout = false);
SponsoredMenuSettings settings = {});
void ShowSponsored(
not_null<Ui::RpWidget*> parent,

View file

@ -947,6 +947,9 @@ historySponsorInfoItem: FlatLabel(defaultFlatLabel) {
minWidth: 136px;
maxHeight: 120px;
}
historySponsorInfoItemDark: FlatLabel(historySponsorInfoItem) {
textFg: mediaviewControlFg;
}
historyHasCustomEmoji: FlatLabel(defaultFlatLabel) {
style: TextStyle(defaultTextStyle) {
font: font(11px);

View file

@ -204,6 +204,7 @@ menuBlueIconGroupCreate: icon {{ "menu/groups_create", lightButtonFg }};
mediaMenuIconStickers: icon {{ "menu/stickers", mediaviewMenuFg }};
mediaMenuIconCancel: icon {{ "menu/cancel", mediaviewMenuFg }};
mediaMenuIconChannel: icon {{ "menu/channel", mediaviewMenuFg }};
mediaMenuIconShowInChat: icon {{ "menu/show_in_chat", mediaviewMenuFg }};
mediaMenuIconShowInFolder: icon {{ "menu/show_in_folder", mediaviewMenuFg }};
mediaMenuIconDownload: icon {{ "menu/download", mediaviewMenuFg }};