Added ability to report sponsored messages.

This commit is contained in:
23rd 2024-03-27 04:47:42 +03:00 committed by John Preston
parent 341b9e4a29
commit 508119a127
5 changed files with 187 additions and 4 deletions

View file

@ -1575,6 +1575,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_button" = "Report";
"lng_report_thanks" = "Thank you! Your report will be reviewed by our team very soon.";
"lng_report_sponsored_hidden" = "Sponsored messages will be hidden.";
"lng_report_sponsored_reported" = "We will review this ad to ensure it matches out {link}.";
"lng_report_sponsored_reported_link" = "Ad Policies and Guidelines";
"lng_channel_add_members" = "Add members";
"lng_channel_add_users" = "Add users";
"lng_channel_add_removed" = "Remove user";
@ -4657,6 +4661,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sponsored_info_menu" = "About this ad";
"lng_sponsored_info_submenu" = "Advertiser: {text}";
"lng_sponsored_menu_revenued_about" = "About These Ads";
"lng_sponsored_menu_revenued_report" = "Report Ad";
"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.";

View file

@ -482,6 +482,83 @@ void SponsoredMessages::clicked(const FullMsgId &fullId) {
)).send();
}
auto SponsoredMessages::createReportCallback(const FullMsgId &fullId)
-> Fn<void(SponsoredReportResult::Id, Fn<void(SponsoredReportResult)>)> {
using TLChoose = MTPDchannels_sponsoredMessageReportResultChooseOption;
using TLAdsHidden = MTPDchannels_sponsoredMessageReportResultAdsHidden;
using TLReported = MTPDchannels_sponsoredMessageReportResultReported;
using Result = SponsoredReportResult;
struct State final {
#ifdef _DEBUG
~State() {
qDebug() << "SponsoredMessages Report ~State().";
}
#endif
mtpRequestId requestId = 0;
};
const auto state = std::make_shared<State>();
return [=](Result::Id optionId, Fn<void(Result)> done) {
const auto entry = find(fullId);
if (!entry) {
return;
}
const auto history = entry->item->history();
const auto channel = history->peer->asChannel();
if (!channel) {
return;
}
state->requestId = _session->api().request(
MTPchannels_ReportSponsoredMessage(
channel->inputChannel,
MTP_bytes(entry->sponsored.randomId),
MTP_bytes(optionId))
).done([=](
const MTPchannels_SponsoredMessageReportResult &result,
mtpRequestId requestId) {
if (state->requestId != requestId) {
return;
}
state->requestId = 0;
done(result.match([&](const TLChoose &data) {
const auto t = qs(data.vtitle());
auto list = Result::Options();
list.reserve(data.voptions().v.size());
for (const auto &tl : data.voptions().v) {
list.emplace_back(Result::Option{
.id = tl.data().voption().v,
.text = qs(tl.data().vtext()),
});
}
return Result{ .options = std::move(list), .title = t };
}, [](const TLAdsHidden &data) -> Result {
return { .result = Result::FinalStep::Hidden };
}, [&](const TLReported &data) -> Result {
const auto it = _data.find(history);
if (it != end(_data)) {
auto &list = it->second.entries;
const auto proj = [&](const Entry &e) {
return e.itemFullId == fullId;
};
list.erase(ranges::remove_if(list, proj), end(list));
}
return { .result = Result::FinalStep::Reported };
}));
}).fail([=](const MTP::Error &error) {
state->requestId = 0;
if (error.type() == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
done({ .result = Result::FinalStep::Premium });
} else {
done({ .error = error.type() });
}
}).send();
};
}
SponsoredMessages::State SponsoredMessages::state(
not_null<History*> history) const {
const auto it = _data.find(history);

View file

@ -22,6 +22,24 @@ namespace Data {
class Session;
struct SponsoredReportResult final {
using Id = QByteArray;
struct Option final {
Id id = 0;
QString text;
};
using Options = std::vector<Option>;
enum class FinalStep {
Hidden,
Reported,
Premium,
};
Options options;
QString title;
QString error;
FinalStep result;
};
struct SponsoredFrom {
PeerData *peer = nullptr;
QString title;
@ -92,6 +110,9 @@ public:
[[nodiscard]] State state(not_null<History*> history) const;
[[nodiscard]] auto createReportCallback(const FullMsgId &fullId)
-> Fn<void(SponsoredReportResult::Id, Fn<void(SponsoredReportResult)>)>;
private:
using OwnedItem = std::unique_ptr<HistoryItem, HistoryItem::Destroyer>;
struct Entry {

View file

@ -7,18 +7,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "menu/menu_sponsored.h"
#include "boxes/premium_preview_box.h"
#include "chat_helpers/compose/compose_show.h"
#include "core/ui_integration.h" // Core::MarkedTextContext.
#include "data/data_premium_limits.h"
#include "data/data_session.h"
#include "data/data_sponsored_messages.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/toast/toast.h"
#include "ui/vertical_list.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/popup_menu.h"
@ -209,11 +212,75 @@ void AboutBox(
}
void ShowReportSponsoredBox(
std::shared_ptr<ChatHelpers::Show> show,
not_null<HistoryItem*> item) {
const auto peer = item->history()->peer;
auto &sponsoredMessages = peer->session().data().sponsoredMessages();
const auto fullId = item->fullId();
const auto report = sponsoredMessages.createReportCallback(fullId);
auto performRequest = [=](
const auto &repeatRequest,
Data::SponsoredReportResult::Id id) -> void {
report(id, [=](const Data::SponsoredReportResult &result) {
if (!result.error.isEmpty()) {
show->showToast(result.error);
}
if (!result.options.empty()) {
show->show(Box([=](not_null<Ui::GenericBox*> box) {
box->setTitle(rpl::single(result.title));
for (const auto &option : result.options) {
const auto button = box->verticalLayout()->add(
object_ptr<Ui::SettingsButton>(
box,
rpl::single(option.text),
st::settingsButtonNoIcon));
button->setClickedCallback([=] {
repeatRequest(repeatRequest, option.id);
});
}
if (!id.isNull()) {
box->addLeftButton(
tr::lng_create_group_back(),
[=] { box->closeBox(); });
}
box->addButton(
tr::lng_close(),
[=] { show->hideLayer(); });
}));
} else {
switch (result.result) {
case Data::SponsoredReportResult::FinalStep::Hidden: {
show->showToast(tr::lng_report_sponsored_hidden(tr::now));
} break;
case Data::SponsoredReportResult::FinalStep::Reported: {
auto text = tr::lng_report_sponsored_reported(
tr::now,
lt_link,
Ui::Text::Link(
tr::lng_report_sponsored_reported_link(tr::now),
u"https://promote.telegram.org/guidelines"_q),
Ui::Text::WithEntities);
show->showToast({ .text = std::move(text) });
} break;
case Data::SponsoredReportResult::FinalStep::Premium: {
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
} break;
}
show->hideLayer();
}
});
};
performRequest(performRequest, Data::SponsoredReportResult::Id());
}
} // namespace
void ShowSponsored(
not_null<Ui::RpWidget*> parent,
std::shared_ptr<Ui::Show> show,
std::shared_ptr<ChatHelpers::Show> show,
not_null<HistoryItem*> item) {
Expects(item->isSponsored());
@ -229,6 +296,16 @@ void ShowSponsored(
show->show(Box(AboutBox, &item->history()->session()));
}, &st::menuIconInfo);
menu->addAction(tr::lng_sponsored_menu_revenued_report(tr::now), [=] {
ShowReportSponsoredBox(show, item);
}, &st::menuIconBlock);
menu->addSeparator(&st::expandedMenuSeparator);
menu->addAction(tr::lng_sponsored_hide_ads(tr::now), [=] {
ShowPremiumPreviewBox(show, PremiumFeature::NoAds);
}, &st::menuIconCancel);
menu->popup(QCursor::pos());
}

View file

@ -7,9 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace ChatHelpers {
class Show;
} // namespace ChatHelpers
namespace Ui {
class RpWidget;
class Show;
} // namespace Ui
class HistoryItem;
@ -18,7 +21,7 @@ namespace Menu {
void ShowSponsored(
not_null<Ui::RpWidget*> parent,
std::shared_ptr<Ui::Show> show,
std::shared_ptr<ChatHelpers::Show> show,
not_null<HistoryItem*> item);
} // namespace Menu