Added support of sponsored messages with revenue to bar.

This commit is contained in:
23rd 2024-10-29 13:27:20 +03:00
parent ae3f16ccbd
commit 7d52787e54
7 changed files with 80 additions and 52 deletions

View file

@ -5200,13 +5200,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sponsored_revenued_subtitle" = "Telegram Ads are very different from ads on other platforms. Ads such as this one:"; "lng_sponsored_revenued_subtitle" = "Telegram Ads are very different from ads on other platforms. Ads such as this one:";
"lng_sponsored_revenued_info1_title" = "Respect Your Privacy"; "lng_sponsored_revenued_info1_title" = "Respect Your Privacy";
"lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them."; "lng_sponsored_revenued_info1_description" = "Ads on Telegram do not use your personal information and are based on the channel in which you see them.";
"lng_sponsored_revenued_info1_bot_description" = "Ads on Telegram do not use your personal information and are based on the mini app in which you see them.";
"lng_sponsored_revenued_info2_title" = "Help the Channel Creator"; "lng_sponsored_revenued_info2_title" = "Help the Channel Creator";
"lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed."; "lng_sponsored_revenued_info2_description" = "50% of the revenue from Telegram Ads goes to the owner of the channel where they are displayed.";
"lng_sponsored_revenued_info2_bot_description" = "50% of the revenue from Telegram Ads goes to the developer of the mini app where they are displayed.";
"lng_sponsored_revenued_info3_title" = "Can Be Removed"; "lng_sponsored_revenued_info3_title" = "Can Be Removed";
"lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers."; "lng_sponsored_revenued_info3_description#one" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
"lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers."; "lng_sponsored_revenued_info3_description#other" = "You can turn off ads by subscribing to {link}, and Level {count} channels can remove them for their subscribers.";
"lng_sponsored_revenued_info3_bot_description" = "You can turn off ads in mini apps by subscribing to {link}.";
"lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?"; "lng_sponsored_revenued_footer_title" = "Can I Launch an Ad?";
"lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}"; "lng_sponsored_revenued_footer_description" = "Anyone can create an ad to display in this channel — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
"lng_sponsored_revenued_footer_bot_description" = "Anyone can create an ad to display in this bot — with minimal budgets. Check out the **Telegram Ad Platform** for details. {link}";
"lng_sponsored_top_bar_hide" = "remove"; "lng_sponsored_top_bar_hide" = "remove";
"lng_telegram_features_url" = "https://t.me/TelegramTips"; "lng_telegram_features_url" = "https://t.me/TelegramTips";

View file

@ -414,6 +414,16 @@ ClickHandlerPtr ReportSponsoredClickHandler(not_null<HistoryItem*> item) {
}); });
} }
ClickHandlerPtr AboutSponsoredClickHandler() {
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
Menu::ShowSponsoredAbout(controller->uiShow(), my.itemId);
}
});
}
MessageFlags FlagsFromMTP( MessageFlags FlagsFromMTP(
MsgId id, MsgId id,
MTPDmessage::Flags flags, MTPDmessage::Flags flags,

View file

@ -148,6 +148,7 @@ ClickHandlerPtr JumpToStoryClickHandler(
[[nodiscard]] ClickHandlerPtr HideSponsoredClickHandler(); [[nodiscard]] ClickHandlerPtr HideSponsoredClickHandler();
[[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler( [[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler(
not_null<HistoryItem*> item); not_null<HistoryItem*> item);
[[nodiscard]] ClickHandlerPtr AboutSponsoredClickHandler();
[[nodiscard]] not_null<HistoryItem*> GenerateJoinedMessage( [[nodiscard]] not_null<HistoryItem*> GenerateJoinedMessage(
not_null<History*> history, not_null<History*> history,

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_sponsored_click_handler.h" #include "history/view/history_view_sponsored_click_handler.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/history_item_helpers.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "menu/menu_sponsored.h" #include "menu/menu_sponsored.h"
@ -144,15 +145,6 @@ constexpr auto kFactcheckAboutDuration = 5 * crl::time(1000);
}); });
} }
[[nodiscard]] ClickHandlerPtr AboutSponsoredClickHandler() {
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
Menu::ShowSponsoredAbout(controller->uiShow());
}
});
}
[[nodiscard]] QString LookupFactcheckCountryIso2( [[nodiscard]] QString LookupFactcheckCountryIso2(
not_null<HistoryItem*> item) { not_null<HistoryItem*> item) {
const auto info = item->Get<HistoryMessageFactcheck>(); const auto info = item->Get<HistoryMessageFactcheck>();

View file

@ -41,11 +41,13 @@ namespace {
void AboutBox( void AboutBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
std::shared_ptr<ChatHelpers::Show> show) { std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId) {
constexpr auto kUrl = "https://promote.telegram.org"_cs; constexpr auto kUrl = "https://promote.telegram.org"_cs;
box->setNoContentMargin(true); box->setNoContentMargin(true);
const auto isChannel = peerIsChannel(fullId.peer);
const auto session = &show->session(); const auto session = &show->session();
const auto content = box->verticalLayout().get(); const auto content = box->verticalLayout().get();
@ -131,29 +133,39 @@ void AboutBox(
}; };
addEntry( addEntry(
tr::lng_sponsored_revenued_info1_title(), tr::lng_sponsored_revenued_info1_title(),
tr::lng_sponsored_revenued_info1_description( (isChannel
Ui::Text::RichLangValue), ? tr::lng_sponsored_revenued_info1_description
: tr::lng_sponsored_revenued_info1_bot_description)(
Ui::Text::RichLangValue),
st::sponsoredAboutPrivacyIcon); st::sponsoredAboutPrivacyIcon);
Ui::AddSkip(content); Ui::AddSkip(content);
Ui::AddSkip(content); Ui::AddSkip(content);
addEntry( addEntry(
tr::lng_sponsored_revenued_info2_title(), tr::lng_sponsored_revenued_info2_title(),
tr::lng_sponsored_revenued_info2_description( (isChannel
Ui::Text::RichLangValue), ? tr::lng_sponsored_revenued_info2_description
: tr::lng_sponsored_revenued_info2_bot_description)(
Ui::Text::RichLangValue),
st::sponsoredAboutSplitIcon); st::sponsoredAboutSplitIcon);
Ui::AddSkip(content); Ui::AddSkip(content);
Ui::AddSkip(content); Ui::AddSkip(content);
auto link = tr::lng_settings_privacy_premium_link(
) | rpl::map([](QString t) {
return Ui::Text::Link(std::move(t), u"internal:"_q);
});
addEntry( addEntry(
tr::lng_sponsored_revenued_info3_title(), tr::lng_sponsored_revenued_info3_title(),
tr::lng_sponsored_revenued_info3_description( isChannel
lt_count, ? tr::lng_sponsored_revenued_info3_description(
rpl::single(float64(levels)), lt_count,
lt_link, rpl::single(float64(levels)),
tr::lng_settings_privacy_premium_link( lt_link,
) | rpl::map([=](QString t) { std::move(link),
return Ui::Text::Link(std::move(t), u"internal:"_q); Ui::Text::RichLangValue)
}), : tr::lng_sponsored_revenued_info3_bot_description(
Ui::Text::RichLangValue), lt_link,
std::move(link),
Ui::Text::RichLangValue),
st::sponsoredAboutRemoveIcon)->setClickHandlerFilter([=]( st::sponsoredAboutRemoveIcon)->setClickHandlerFilter([=](
const auto &...) { const auto &...) {
ShowPremiumPreviewBox(show, PremiumFeature::NoAds); ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
@ -185,16 +197,18 @@ void AboutBox(
box->addRow( box->addRow(
Ui::CreateLabelWithCustomEmoji( Ui::CreateLabelWithCustomEmoji(
content, content,
tr::lng_sponsored_revenued_footer_description( (isChannel
lt_link, ? tr::lng_sponsored_revenued_footer_description
tr::lng_channel_earn_about_link( : tr::lng_sponsored_revenued_footer_bot_description)(
lt_emoji, lt_link,
rpl::single(arrow), tr::lng_channel_earn_about_link(
Ui::Text::RichLangValue lt_emoji,
) | rpl::map([=](TextWithEntities text) { rpl::single(arrow),
return Ui::Text::Link(std::move(text), kUrl.utf16()); Ui::Text::RichLangValue
}), ) | rpl::map([=](TextWithEntities t) {
Ui::Text::RichLangValue), return Ui::Text::Link(std::move(t), kUrl.utf16());
}),
Ui::Text::RichLangValue),
{ .session = session }, { .session = session },
st::channelEarnLearnDescription))->resizeToWidth(available); st::channelEarnLearnDescription))->resizeToWidth(available);
} }
@ -309,7 +323,7 @@ void FillSponsored(
const auto session = &show->session(); const auto session = &show->session();
addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] { addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
show->show(Box(AboutBox, show)); show->show(Box(AboutBox, show, fullId));
}, (mediaViewer ? &st::mediaMenuIconInfo : &st::menuIconInfo)); }, (mediaViewer ? &st::mediaMenuIconInfo : &st::menuIconInfo));
addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] { addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
@ -352,9 +366,11 @@ void ShowSponsored(
menu->popup(QCursor::pos()); menu->popup(QCursor::pos());
} }
void ShowSponsoredAbout(std::shared_ptr<ChatHelpers::Show> show) { void ShowSponsoredAbout(
std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) { show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
AboutBox(box, show); AboutBox(box, show, fullId);
})); }));
} }

View file

@ -34,6 +34,8 @@ void ShowSponsored(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId); const FullMsgId &fullId);
void ShowSponsoredAbout(std::shared_ptr<ChatHelpers::Show> show); void ShowSponsoredAbout(
std::shared_ptr<ChatHelpers::Show> show,
const FullMsgId &fullId);
} // namespace Menu } // namespace Menu

View file

@ -42,13 +42,14 @@ struct Colors final {
using ColorFactory = Fn<Colors()>; using ColorFactory = Fn<Colors()>;
class RemoveButton final : public Ui::RippleButton { class BadgeButton final : public Ui::RippleButton {
public: public:
RemoveButton( BadgeButton(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
tr::phrase<> text,
ColorFactory cache) ColorFactory cache)
: Ui::RippleButton(parent, st::defaultRippleAnimation) { : Ui::RippleButton(parent, st::defaultRippleAnimation) {
tr::lng_sponsored_top_bar_hide( text(
) | rpl::start_with_next([this](const QString &t) { ) | rpl::start_with_next([this](const QString &t) {
const auto height = st::stickersHeaderBadgeFont->height; const auto height = st::stickersHeaderBadgeFont->height;
resize( resize(
@ -56,7 +57,7 @@ public:
height); height);
update(); update();
}, lifetime()); }, lifetime());
paintRequest() | rpl::start_with_next([this, cache] { paintRequest() | rpl::start_with_next([this, cache, text] {
auto p = QPainter(this); auto p = QPainter(this);
const auto colors = cache(); const auto colors = cache();
const auto r = rect(); const auto r = rect();
@ -70,10 +71,7 @@ public:
p.drawRoundedRect(r, r.height() / 2, r.height() / 2); p.drawRoundedRect(r, r.height() / 2, r.height() / 2);
p.setFont(st::stickersHeaderBadgeFont); p.setFont(st::stickersHeaderBadgeFont);
p.setPen(colors.fg); p.setPen(colors.fg);
p.drawText( p.drawText(r, text(tr::now), style::al_center);
r,
tr::lng_sponsored_top_bar_hide(tr::now),
style::al_center);
}, lifetime()); }, lifetime());
} }
@ -199,14 +197,19 @@ void FillSponsoredMessageBar(
state->rightPhoto->subscribeToUpdates(callback); state->rightPhoto->subscribeToUpdates(callback);
callback(); callback();
} }
const auto removeButton = Ui::CreateChild<RemoveButton>( const auto badgeButton = Ui::CreateChild<BadgeButton>(
widget, widget,
from.canReport
? tr::lng_sponsored_message_revenue_button
: tr::lng_sponsored_top_bar_hide,
GenerateReplyColorCallback( GenerateReplyColorCallback(
widget, widget,
fullId, fullId,
from.colorIndex ? from.colorIndex : 4/*blue*/)); from.colorIndex ? from.colorIndex : 4/*blue*/));
const auto handler = HideSponsoredClickHandler(); const auto handler = from.canReport
removeButton->setClickedCallback([=] { ? AboutSponsoredClickHandler()
: HideSponsoredClickHandler();
badgeButton->setClickedCallback([=] {
if (const auto controller = FindSessionController(widget)) { if (const auto controller = FindSessionController(widget)) {
ActivateClickHandler(widget, handler, { ActivateClickHandler(widget, handler, {
.other = QVariant::fromValue(ClickHandlerContext{ .other = QVariant::fromValue(ClickHandlerContext{
@ -217,7 +220,7 @@ void FillSponsoredMessageBar(
}); });
} }
}); });
removeButton->show(); badgeButton->show();
const auto draw = [=](QPainter &p) { const auto draw = [=](QPainter &p) {
const auto r = widget->rect(); const auto r = widget->rect();
@ -237,14 +240,14 @@ void FillSponsoredMessageBar(
const auto hasSecondLineTitle = (titleRight const auto hasSecondLineTitle = (titleRight
> (availableWidth > (availableWidth
- state->contentTitle.maxWidth() - state->contentTitle.maxWidth()
- removeButton->width())); - badgeButton->width()));
p.setPen(st::windowActiveTextFg); p.setPen(st::windowActiveTextFg);
state->title.draw(p, { state->title.draw(p, {
.position = QPoint(leftPadding, topPadding), .position = QPoint(leftPadding, topPadding),
.outerWidth = availableWidth, .outerWidth = availableWidth,
.availableWidth = availableWidth, .availableWidth = availableWidth,
}); });
removeButton->moveToLeft( badgeButton->moveToLeft(
hasSecondLineTitle hasSecondLineTitle
? titleRight ? titleRight
: std::min( : std::min(
@ -257,7 +260,7 @@ void FillSponsoredMessageBar(
: 0) : 0)
- rightPadding), - rightPadding),
topPadding topPadding
+ (titleSt.font->height - removeButton->height()) / 2); + (titleSt.font->height - badgeButton->height()) / 2);
p.setPen(st::windowFg); p.setPen(st::windowFg);
{ {
const auto left = hasSecondLineTitle ? leftPadding : titleRight; const auto left = hasSecondLineTitle ? leftPadding : titleRight;