Added menu with about box to sponsored messages that can be reported.
|
@ -1141,6 +1141,8 @@ PRIVATE
|
|||
menu/menu_mute.h
|
||||
menu/menu_send.cpp
|
||||
menu/menu_send.h
|
||||
menu/menu_sponsored.cpp
|
||||
menu/menu_sponsored.h
|
||||
menu/menu_ttl_validator.cpp
|
||||
menu/menu_ttl_validator.h
|
||||
mtproto/config_loader.cpp
|
||||
|
|
BIN
Telegram/Resources/icons/sponsored/large_about.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/sponsored/large_about@2x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
Telegram/Resources/icons/sponsored/large_about@3x.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
Telegram/Resources/icons/sponsored/privacy_about.png
Normal file
After Width: | Height: | Size: 534 B |
BIN
Telegram/Resources/icons/sponsored/privacy_about@2x.png
Normal file
After Width: | Height: | Size: 928 B |
BIN
Telegram/Resources/icons/sponsored/privacy_about@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/sponsored/remove_about.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
Telegram/Resources/icons/sponsored/remove_about@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/sponsored/remove_about@3x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Telegram/Resources/icons/sponsored/revenue_split.png
Normal file
After Width: | Height: | Size: 651 B |
BIN
Telegram/Resources/icons/sponsored/revenue_split@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/sponsored/revenue_split@3x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
|
@ -4656,6 +4656,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_sponsored_info_description2" = "Sponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate – together.";
|
||||
"lng_sponsored_info_menu" = "About this ad";
|
||||
"lng_sponsored_info_submenu" = "Advertiser: {text}";
|
||||
"lng_sponsored_menu_revenued_about" = "About These Ads";
|
||||
"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 abased on the channel 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_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_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_telegram_features_url" = "https://t.me/TelegramTips";
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "main/main_domain.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "menu/menu_sponsored.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -367,8 +368,15 @@ ClickHandlerPtr HideSponsoredClickHandler() {
|
|||
});
|
||||
}
|
||||
|
||||
ClickHandlerPtr ReportSponsoredClickHandler() {
|
||||
ClickHandlerPtr ReportSponsoredClickHandler(not_null<HistoryItem*> item) {
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
Menu::ShowSponsored(
|
||||
controller->widget(),
|
||||
controller->uiShow(),
|
||||
item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,8 @@ ClickHandlerPtr JumpToStoryClickHandler(
|
|||
not_null<PeerData*> peer,
|
||||
StoryId storyId);
|
||||
[[nodiscard]] ClickHandlerPtr HideSponsoredClickHandler();
|
||||
[[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler();
|
||||
[[nodiscard]] ClickHandlerPtr ReportSponsoredClickHandler(
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
[[nodiscard]] not_null<HistoryItem*> GenerateJoinedMessage(
|
||||
not_null<History*> history,
|
||||
|
|
|
@ -441,7 +441,7 @@ Message::Message(
|
|||
_rightAction = std::make_unique<RightAction>();
|
||||
_rightAction->second = std::make_unique<SecondRightAction>();
|
||||
|
||||
_rightAction->second->link = ReportSponsoredClickHandler();
|
||||
_rightAction->second->link = ReportSponsoredClickHandler(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,3 +108,8 @@ channelEarnLearnDescription: FlatLabel(defaultFlatLabel) {
|
|||
minWidth: 280px;
|
||||
align: align(top);
|
||||
}
|
||||
|
||||
sponsoredAboutTitleIcon: icon {{ "sponsored/large_about", activeButtonFg }};
|
||||
sponsoredAboutPrivacyIcon: icon {{ "sponsored/privacy_about", boxTextFg }};
|
||||
sponsoredAboutRemoveIcon: icon {{ "sponsored/remove_about", boxTextFg }};
|
||||
sponsoredAboutSplitIcon: icon {{ "sponsored/revenue_split", boxTextFg }};
|
||||
|
|
235
Telegram/SourceFiles/menu/menu_sponsored.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "menu/menu_sponsored.h"
|
||||
|
||||
#include "core/ui_integration.h" // Core::MarkedTextContext.
|
||||
#include "data/data_premium_limits.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "styles/style_channel_earn.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_premium.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
namespace Menu {
|
||||
namespace {
|
||||
|
||||
void AboutBox(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session) {
|
||||
constexpr auto kUrl = "https://promote.telegram.org"_cs;
|
||||
|
||||
box->setNoContentMargin(true);
|
||||
|
||||
const auto content = box->verticalLayout().get();
|
||||
const auto levels = Data::LevelLimits(session)
|
||||
.channelRestrictSponsoredLevelMin();
|
||||
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
{
|
||||
const auto &icon = st::sponsoredAboutTitleIcon;
|
||||
const auto rect = Rect(icon.size() * 1.4);
|
||||
auto owned = object_ptr<Ui::RpWidget>(content);
|
||||
owned->resize(rect.size());
|
||||
const auto widget = box->addRow(object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
std::move(owned)))->entity();
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = Painter(widget);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::activeButtonBg);
|
||||
p.drawEllipse(rect);
|
||||
icon.paintInCenter(p, rect);
|
||||
}, widget->lifetime());
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
box->addRow(object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_sponsored_menu_revenued_about(),
|
||||
st::boxTitle)));
|
||||
Ui::AddSkip(content);
|
||||
box->addRow(object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_sponsored_revenued_subtitle(),
|
||||
st::channelEarnLearnDescription)));
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
{
|
||||
const auto padding = QMargins(
|
||||
st::settingsButton.padding.left(),
|
||||
st::boxRowPadding.top(),
|
||||
st::boxRowPadding.right(),
|
||||
st::boxRowPadding.bottom());
|
||||
const auto addEntry = [&](
|
||||
rpl::producer<QString> title,
|
||||
rpl::producer<TextWithEntities> about,
|
||||
const style::icon &icon) {
|
||||
const auto top = content->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
std::move(title),
|
||||
st::channelEarnSemiboldLabel),
|
||||
padding);
|
||||
Ui::AddSkip(content, st::channelEarnHistoryThreeSkip);
|
||||
content->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
std::move(about),
|
||||
st::channelEarnHistoryRecipientLabel),
|
||||
padding);
|
||||
const auto left = Ui::CreateChild<Ui::RpWidget>(
|
||||
box->verticalLayout().get());
|
||||
left->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = Painter(left);
|
||||
icon.paint(p, 0, 0, left->width());
|
||||
}, left->lifetime());
|
||||
left->resize(icon.size());
|
||||
top->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &g) {
|
||||
left->moveToLeft(
|
||||
(g.left() - left->width()) / 2,
|
||||
g.top() + st::channelEarnHistoryThreeSkip);
|
||||
}, left->lifetime());
|
||||
};
|
||||
addEntry(
|
||||
tr::lng_sponsored_revenued_info1_title(),
|
||||
tr::lng_sponsored_revenued_info1_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),
|
||||
st::sponsoredAboutSplitIcon);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
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(t, kUrl.utf8());
|
||||
}),
|
||||
Ui::Text::RichLangValue),
|
||||
st::sponsoredAboutRemoveIcon);
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
{
|
||||
box->addRow(
|
||||
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||
content,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
tr::lng_sponsored_revenued_footer_title(),
|
||||
st::boxTitle)));
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
{
|
||||
const auto arrow = Ui::Text::SingleCustomEmoji(
|
||||
session->data().customEmojiManager().registerInternalEmoji(
|
||||
st::topicButtonArrow,
|
||||
st::channelEarnLearnArrowMargins,
|
||||
false));
|
||||
const auto label = box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
st::channelEarnLearnDescription));
|
||||
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.utf8());
|
||||
}),
|
||||
Ui::Text::RichLangValue
|
||||
) | rpl::start_with_next([=, l = label](
|
||||
TextWithEntities t) {
|
||||
l->setMarkedText(
|
||||
std::move(t),
|
||||
Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = [=] { l->update(); },
|
||||
});
|
||||
l->resizeToWidth(box->width()
|
||||
- rect::m::sum::h(st::boxRowPadding));
|
||||
}, label->lifetime());
|
||||
}
|
||||
Ui::AddSkip(content);
|
||||
Ui::AddSkip(content);
|
||||
{
|
||||
const auto &st = st::premiumPreviewDoubledLimitsBox;
|
||||
box->setStyle(st);
|
||||
auto button = object_ptr<Ui::RoundButton>(
|
||||
box,
|
||||
tr::lng_box_ok(),
|
||||
st::defaultActiveButton);
|
||||
button->resizeToWidth(box->width()
|
||||
- st.buttonPadding.left()
|
||||
- st.buttonPadding.left());
|
||||
button->setClickedCallback([=] { box->closeBox(); });
|
||||
box->addButton(std::move(button));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ShowSponsored(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<HistoryItem*> item) {
|
||||
Expects(item->isSponsored());
|
||||
|
||||
struct State final {
|
||||
};
|
||||
const auto state = std::make_shared<State>();
|
||||
|
||||
const auto menu = Ui::CreateChild<Ui::PopupMenu>(
|
||||
parent.get(),
|
||||
st::popupMenuWithIcons);
|
||||
|
||||
menu->addAction(tr::lng_sponsored_menu_revenued_about(tr::now), [=] {
|
||||
show->show(Box(AboutBox, &item->history()->session()));
|
||||
}, &st::menuIconInfo);
|
||||
|
||||
menu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
} // namespace Menu
|
24
Telegram/SourceFiles/menu/menu_sponsored.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
class Show;
|
||||
} // namespace Ui
|
||||
|
||||
class HistoryItem;
|
||||
|
||||
namespace Menu {
|
||||
|
||||
void ShowSponsored(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
} // namespace Menu
|