From 7d52787e5484b5ef605e8ddecd847a2a8db6c3e5 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 29 Oct 2024 13:27:20 +0300 Subject: [PATCH] Added support of sponsored messages with revenue to bar. --- Telegram/Resources/langs/lang.strings | 4 ++ .../history/history_item_helpers.cpp | 10 +++ .../history/history_item_helpers.h | 1 + .../view/media/history_view_web_page.cpp | 10 +-- Telegram/SourceFiles/menu/menu_sponsored.cpp | 70 ++++++++++++------- Telegram/SourceFiles/menu/menu_sponsored.h | 4 +- .../ui/chat/sponsored_message_bar.cpp | 33 +++++---- 7 files changed, 80 insertions(+), 52 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index be8a9d21e..f72f4cbd3 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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"; diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index ea8f19eda..751a81f39 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -414,6 +414,16 @@ ClickHandlerPtr ReportSponsoredClickHandler(not_null item) { }); } +ClickHandlerPtr AboutSponsoredClickHandler() { + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + Menu::ShowSponsoredAbout(controller->uiShow(), my.itemId); + } + }); +} + + MessageFlags FlagsFromMTP( MsgId id, MTPDmessage::Flags flags, diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index dd5121dbe..ba5bd2cda 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -148,6 +148,7 @@ ClickHandlerPtr JumpToStoryClickHandler( [[nodiscard]] ClickHandlerPtr HideSponsoredClickHandler(); [[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler( not_null item); +[[nodiscard]] ClickHandlerPtr AboutSponsoredClickHandler(); [[nodiscard]] not_null GenerateJoinedMessage( not_null history, diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 65f9a8cb0..960cc51a0 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -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([=](ClickContext context) { - const auto my = context.other.value(); - if (const auto controller = my.sessionWindow.get()) { - Menu::ShowSponsoredAbout(controller->uiShow()); - } - }); -} - [[nodiscard]] QString LookupFactcheckCountryIso2( not_null item) { const auto info = item->Get(); diff --git a/Telegram/SourceFiles/menu/menu_sponsored.cpp b/Telegram/SourceFiles/menu/menu_sponsored.cpp index 4d5564793..274a8ddc0 100644 --- a/Telegram/SourceFiles/menu/menu_sponsored.cpp +++ b/Telegram/SourceFiles/menu/menu_sponsored.cpp @@ -41,11 +41,13 @@ namespace { void AboutBox( not_null box, - std::shared_ptr show) { + std::shared_ptr 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 show) { +void ShowSponsoredAbout( + std::shared_ptr show, + const FullMsgId &fullId) { show->showBox(Box([=](not_null box) { - AboutBox(box, show); + AboutBox(box, show, fullId); })); } diff --git a/Telegram/SourceFiles/menu/menu_sponsored.h b/Telegram/SourceFiles/menu/menu_sponsored.h index a1dc05be3..12323047e 100644 --- a/Telegram/SourceFiles/menu/menu_sponsored.h +++ b/Telegram/SourceFiles/menu/menu_sponsored.h @@ -34,6 +34,8 @@ void ShowSponsored( std::shared_ptr show, const FullMsgId &fullId); -void ShowSponsoredAbout(std::shared_ptr show); +void ShowSponsoredAbout( + std::shared_ptr show, + const FullMsgId &fullId); } // namespace Menu diff --git a/Telegram/SourceFiles/ui/chat/sponsored_message_bar.cpp b/Telegram/SourceFiles/ui/chat/sponsored_message_bar.cpp index 5abf8f556..e16268c8a 100644 --- a/Telegram/SourceFiles/ui/chat/sponsored_message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/sponsored_message_bar.cpp @@ -42,13 +42,14 @@ struct Colors final { using ColorFactory = Fn; -class RemoveButton final : public Ui::RippleButton { +class BadgeButton final : public Ui::RippleButton { public: - RemoveButton( + BadgeButton( not_null 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( + const auto badgeButton = Ui::CreateChild( 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;