Added possible info about sponsors to menu from sponsored messages.

This commit is contained in:
23rd 2023-03-01 16:28:06 +03:00
parent 5a43e7718a
commit ae5f2add0e
5 changed files with 105 additions and 10 deletions

View File

@ -3552,6 +3552,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sponsored_title" = "What are sponsored messages?";
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties cant spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
"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_telegram_features_url" = "https://t.me/TelegramTips";

View File

@ -17,8 +17,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "history/view/history_view_element.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/image/image_location_factory.h"
#include "ui/text/text_utilities.h" // Ui::Text::RichLangValue.
namespace Data {
namespace {
@ -313,6 +315,15 @@ void SponsoredMessages::append(
return makeFrom(chat);
});
}();
auto sponsorInfo = data.vsponsor_info()
? tr::lng_sponsored_info_submenu(
tr::now,
lt_text,
{ .text = qs(*data.vsponsor_info()) },
Ui::Text::RichLangValue)
: TextWithEntities();
auto additionalInfo = TextWithEntities::Simple(
data.vadditional_info() ? qs(*data.vadditional_info()) : QString());
auto sharedMessage = SponsoredMessage{
.randomId = randomId,
.from = from,
@ -325,6 +336,8 @@ void SponsoredMessages::append(
.history = history,
.msgId = data.vchannel_post().value_or_empty(),
.chatInviteHash = hash,
.sponsorInfo = std::move(sponsorInfo),
.additionalInfo = std::move(additionalInfo),
};
list.entries.push_back({ nullptr, std::move(sharedMessage) });
}
@ -393,11 +406,23 @@ SponsoredMessages::Details SponsoredMessages::lookupDetails(
if (!entryPtr) {
return {};
}
const auto &hash = entryPtr->sponsored.chatInviteHash;
const auto &data = entryPtr->sponsored;
const auto &hash = data.chatInviteHash;
using InfoList = std::vector<TextWithEntities>;
const auto info = (!data.sponsorInfo.text.isEmpty()
&& !data.additionalInfo.text.isEmpty())
? InfoList{ data.sponsorInfo, data.additionalInfo }
: !data.sponsorInfo.text.isEmpty()
? InfoList{ data.sponsorInfo }
: !data.additionalInfo.text.isEmpty()
? InfoList{ data.additionalInfo }
: InfoList{};
return {
.hash = hash.isEmpty() ? std::nullopt : std::make_optional(hash),
.peer = entryPtr->sponsored.from.peer,
.msgId = entryPtr->sponsored.msgId,
.peer = data.from.peer,
.msgId = data.msgId,
.info = std::move(info),
};
}

View File

@ -42,6 +42,8 @@ struct SponsoredMessage {
History *history = nullptr;
MsgId msgId;
QString chatInviteHash;
TextWithEntities sponsorInfo;
TextWithEntities additionalInfo;
};
class SponsoredMessages final {
@ -55,6 +57,7 @@ public:
std::optional<QString> hash;
PeerData *peer = nullptr;
MsgId msgId;
std::vector<TextWithEntities> info;
};
using RandomId = QByteArray;
explicit SponsoredMessages(not_null<Session*> owner);

View File

@ -28,6 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_components.h"
#include "history/history_item_text.h"
#include "ui/chat/chat_style.h"
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/widgets/menu/menu_multiline_action.h"
#include "ui/widgets/popup_menu.h"
#include "ui/image/image.h"
#include "ui/toasts/common_toasts.h"
@ -130,6 +132,72 @@ int BinarySearchBlocksOrItems(const T &list, int edge) {
return start;
}
void FillSponsoredMessagesMenu(
not_null<Window::SessionController*> controller,
FullMsgId itemId,
not_null<Ui::PopupMenu*> menu) {
const auto &data = controller->session().data().sponsoredMessages();
const auto info = data.lookupDetails(itemId).info;
const auto toastParent = Window::Show(controller).toastParent();
if (!info.empty()) {
auto fillSubmenu = [&](not_null<Ui::PopupMenu*> menu) {
const auto allText = ranges::accumulate(
info,
TextWithEntities(),
[](TextWithEntities a, TextWithEntities b) {
return a.text.isEmpty() ? b : a.append('\n').append(b);
}).text;
const auto callback = [=] {
QGuiApplication::clipboard()->setText(allText);
Ui::ShowMultilineToast({
.parentOverride = toastParent,
.text = { tr::lng_text_copied(tr::now) },
});
};
for (const auto &i : info) {
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
menu,
st::defaultMenu,
st::historyHasCustomEmoji,
st::historyHasCustomEmojiPosition,
base::duplicate(i));
item->clicks(
) | rpl::start_with_next(callback, menu->lifetime());
menu->addAction(std::move(item));
if (i != info.back()) {
menu->addSeparator();
}
}
};
using namespace Ui::Menu;
CreateAddActionCallback(menu)(MenuCallback::Args{
.text = tr::lng_sponsored_info_menu(tr::now),
.handler = nullptr,
.icon = nullptr,
.fillSubmenu = std::move(fillSubmenu),
});
menu->addSeparator();
}
{
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
menu,
st::menuWithIcons,
st::historyHasCustomEmoji,
st::historySponsoredAboutMenuLabelPosition,
TextWithEntities{ tr::lng_sponsored_title(tr::now) },
&st::menuIconInfo);
item->clicks(
) | rpl::start_with_next([=] {
controller->show(Box(Ui::AboutSponsoredBox));
}, item->lifetime());
menu->addAction(std::move(item));
}
menu->addSeparator();
menu->addAction(tr::lng_sponsored_hide_ads(tr::now), [=] {
Settings::ShowPremium(controller, "no_ads");
}, &st::menuIconBlock);
}
} // namespace
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -2415,13 +2483,8 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
if (item->isSponsored()) {
_menu->addAction(tr::lng_sponsored_title({}), [=] {
_controller->show(Box(Ui::AboutSponsoredBox));
}, &st::menuIconInfo);
_menu->addSeparator();
_menu->addAction(tr::lng_sponsored_hide_ads({}), [=] {
Settings::ShowPremium(_controller, "no_ads");
}, &st::menuIconBlock);
const auto itemId = item->fullId();
FillSponsoredMessagesMenu(controller, itemId, _menu);
}
if (!item->isService() && view && actionText.isEmpty()) {
if (!hasCopyRestriction(item)

View File

@ -1251,6 +1251,8 @@ historyTranslateSettings: IconButton(defaultIconButton) {
}
historyTranslateMenuPosition: point(-6px, 30px);
historySponsoredAboutMenuLabelPosition: point(54px, 4px);
historySendDisabled: FlatLabel(defaultFlatLabel) {
minWidth: 10px;
maxHeight: 20px;