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_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_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_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_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_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_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_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(
MsgId id,
MTPDmessage::Flags flags,

View file

@ -148,6 +148,7 @@ ClickHandlerPtr JumpToStoryClickHandler(
[[nodiscard]] ClickHandlerPtr HideSponsoredClickHandler();
[[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler(
not_null<HistoryItem*> item);
[[nodiscard]] ClickHandlerPtr AboutSponsoredClickHandler();
[[nodiscard]] not_null<HistoryItem*> GenerateJoinedMessage(
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/history.h"
#include "history/history_item_components.h"
#include "history/history_item_helpers.h"
#include "lang/lang_keys.h"
#include "main/main_session.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(
not_null<HistoryItem*> item) {
const auto info = item->Get<HistoryMessageFactcheck>();

View file

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

View file

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

View file

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