Support cloud-saved paid reaction privacy.

This commit is contained in:
John Preston 2024-08-30 10:31:57 +04:00
parent 2b185d491b
commit d81547f091
11 changed files with 102 additions and 29 deletions

View file

@ -115,6 +115,28 @@ rpl::producer<bool> GlobalPrivacy::newRequirePremium() const {
return _newRequirePremium.value(); return _newRequirePremium.value();
} }
void GlobalPrivacy::loadPaidReactionAnonymous() {
if (_paidReactionAnonymousLoaded) {
return;
}
_paidReactionAnonymousLoaded = true;
_api.request(MTPmessages_GetPaidReactionPrivacy(
)).done([=](const MTPUpdates &result) {
_session->api().applyUpdates(result);
}).send();
}
void GlobalPrivacy::updatePaidReactionAnonymous(bool value) {
_paidReactionAnonymous = value;
}
bool GlobalPrivacy::paidReactionAnonymousCurrent() const {
return _paidReactionAnonymous.current();
}
rpl::producer<bool> GlobalPrivacy::paidReactionAnonymous() const {
return _paidReactionAnonymous.value();
}
void GlobalPrivacy::updateArchiveAndMute(bool value) { void GlobalPrivacy::updateArchiveAndMute(bool value) {
update( update(

View file

@ -49,6 +49,11 @@ public:
[[nodiscard]] bool newRequirePremiumCurrent() const; [[nodiscard]] bool newRequirePremiumCurrent() const;
[[nodiscard]] rpl::producer<bool> newRequirePremium() const; [[nodiscard]] rpl::producer<bool> newRequirePremium() const;
void loadPaidReactionAnonymous();
void updatePaidReactionAnonymous(bool value);
[[nodiscard]] bool paidReactionAnonymousCurrent() const;
[[nodiscard]] rpl::producer<bool> paidReactionAnonymous() const;
private: private:
void apply(const MTPGlobalPrivacySettings &data); void apply(const MTPGlobalPrivacySettings &data);
@ -67,7 +72,9 @@ private:
rpl::variable<bool> _showArchiveAndMute = false; rpl::variable<bool> _showArchiveAndMute = false;
rpl::variable<bool> _hideReadTime = false; rpl::variable<bool> _hideReadTime = false;
rpl::variable<bool> _newRequirePremium = false; rpl::variable<bool> _newRequirePremium = false;
rpl::variable<bool> _paidReactionAnonymous = false;
std::vector<Fn<void()>> _callbacks; std::vector<Fn<void()>> _callbacks;
bool _paidReactionAnonymousLoaded = false;
}; };

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_authorizations.h" #include "api/api_authorizations.h"
#include "api/api_user_names.h" #include "api/api_user_names.h"
#include "api/api_chat_participants.h" #include "api/api_chat_participants.h"
#include "api/api_global_privacy.h"
#include "api/api_ringtones.h" #include "api/api_ringtones.h"
#include "api/api_text_entities.h" #include "api/api_text_entities.h"
#include "api/api_user_privacy.h" #include "api/api_user_privacy.h"
@ -2622,6 +2623,12 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->credits().apply(data); _session->credits().apply(data);
} break; } break;
case mtpc_updatePaidReactionPrivacy: {
const auto &data = update.c_updatePaidReactionPrivacy();
_session->api().globalPrivacy().updatePaidReactionAnonymous(
mtpIsTrue(data.vprivate()));
} break;
} }
} }

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "data/data_channel.h" #include "data/data_channel.h"
#include "api/api_global_privacy.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_channel_admins.h" #include "data/data_channel_admins.h"
#include "data/data_user.h" #include "data/data_user.h"
@ -971,6 +972,9 @@ PeerId ChannelData::groupCallDefaultJoinAs() const {
void ChannelData::setAllowedReactions(Data::AllowedReactions value) { void ChannelData::setAllowedReactions(Data::AllowedReactions value) {
if (_allowedReactions != value) { if (_allowedReactions != value) {
if (value.paidEnabled) {
session().api().globalPrivacy().loadPaidReactionAnonymous();
}
const auto enabled = [](const Data::AllowedReactions &allowed) { const auto enabled = [](const Data::AllowedReactions &allowed) {
return (allowed.type != Data::AllowedReactionsType::Some) return (allowed.type != Data::AllowedReactionsType::Some)
|| !allowed.some.empty() || !allowed.some.empty()

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "api/api_global_privacy.h"
#include "chat_helpers/stickers_lottie.h" #include "chat_helpers/stickers_lottie.h"
#include "core/application.h" #include "core/application.h"
#include "history/history.h" #include "history/history.h"
@ -152,6 +153,10 @@ constexpr auto kPaidAccumulatePeriod = 5 * crl::time(1000) + 500;
return (i != end(top)) && i->my; return (i != end(top)) && i->my;
} }
[[nodiscard]] std::optional<bool> MaybeAnonymous(uint32 privacySet, uint32 anonymous) {
return privacySet ? (anonymous == 1) : std::optional<bool>();
}
} // namespace } // namespace
PossibleItemReactionsRef LookupPossibleReactions( PossibleItemReactionsRef LookupPossibleReactions(
@ -1734,6 +1739,7 @@ void Reactions::sendPaidPrivacyRequest(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
PaidReactionSend send) { PaidReactionSend send) {
Expects(!_sendingPaid.contains(item)); Expects(!_sendingPaid.contains(item));
Expects(send.anonymous.has_value());
Expects(!send.count); Expects(!send.count);
const auto id = item->fullId(); const auto id = item->fullId();
@ -1742,7 +1748,7 @@ void Reactions::sendPaidPrivacyRequest(
MTPmessages_TogglePaidReactionPrivacy( MTPmessages_TogglePaidReactionPrivacy(
item->history()->peer->input, item->history()->peer->input,
MTP_int(id.msg), MTP_int(id.msg),
MTP_bool(send.anonymous)) MTP_bool(*send.anonymous))
).done([=] { ).done([=] {
if (const auto item = _owner->message(id)) { if (const auto item = _owner->message(id)) {
if (_sendingPaid.remove(item)) { if (_sendingPaid.remove(item)) {
@ -1776,12 +1782,12 @@ void Reactions::sendPaidRequest(
auto &api = _owner->session().api(); auto &api = _owner->session().api();
using Flag = MTPmessages_SendPaidReaction::Flag; using Flag = MTPmessages_SendPaidReaction::Flag;
const auto requestId = api.request(MTPmessages_SendPaidReaction( const auto requestId = api.request(MTPmessages_SendPaidReaction(
MTP_flags(Flag::f_private), MTP_flags(send.anonymous ? Flag::f_private : Flag()),
item->history()->peer->input, item->history()->peer->input,
MTP_int(id.msg), MTP_int(id.msg),
MTP_int(send.count), MTP_int(send.count),
MTP_long(randomId), MTP_long(randomId),
MTP_bool(send.anonymous) MTP_bool(send.anonymous.value_or(false))
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
if (const auto item = _owner->message(id)) { if (const auto item = _owner->message(id)) {
if (_sendingPaid.remove(item)) { if (_sendingPaid.remove(item)) {
@ -1829,9 +1835,13 @@ MessageReactions::~MessageReactions() {
cancelScheduledPaid(); cancelScheduledPaid();
if (const auto paid = _paid.get()) { if (const auto paid = _paid.get()) {
if (paid->sending > 0) { if (paid->sending > 0) {
finishPaidSending( finishPaidSending({
{ int(paid->sending), (paid->sendingAnonymous == 1) }, .count = int(paid->sending),
false); .valid = true,
.anonymous = MaybeAnonymous(
paid->sendingPrivacySet,
paid->sendingAnonymous),
}, false);
} }
} }
} }
@ -2192,7 +2202,9 @@ void MessageReactions::markRead() {
} }
} }
void MessageReactions::scheduleSendPaid(int count, bool anonymous) { void MessageReactions::scheduleSendPaid(
int count,
std::optional<bool> anonymous) {
Expects(count >= 0); Expects(count >= 0);
if (!_paid) { if (!_paid) {
@ -2200,7 +2212,10 @@ void MessageReactions::scheduleSendPaid(int count, bool anonymous) {
} }
_paid->scheduled += count; _paid->scheduled += count;
_paid->scheduledFlag = 1; _paid->scheduledFlag = 1;
_paid->scheduledAnonymous = anonymous ? 1 : 0; if (anonymous.has_value()) {
_paid->scheduledAnonymous = anonymous.value_or(false) ? 1 : 0;
_paid->scheduledPrivacySet = anonymous.has_value();
}
if (count > 0) { if (count > 0) {
_item->history()->session().credits().lock(count); _item->history()->session().credits().lock(count);
} }
@ -2220,6 +2235,7 @@ void MessageReactions::cancelScheduledPaid() {
_paid->scheduled = 0; _paid->scheduled = 0;
_paid->scheduledFlag = 0; _paid->scheduledFlag = 0;
_paid->scheduledAnonymous = 0; _paid->scheduledAnonymous = 0;
_paid->scheduledPrivacySet = 0;
} }
if (!_paid->sendingFlag && _paid->top.empty()) { if (!_paid->sendingFlag && _paid->top.empty()) {
_paid = nullptr; _paid = nullptr;
@ -2234,13 +2250,17 @@ PaidReactionSend MessageReactions::startPaidSending() {
_paid->sending = _paid->scheduled; _paid->sending = _paid->scheduled;
_paid->sendingFlag = _paid->scheduledFlag; _paid->sendingFlag = _paid->scheduledFlag;
_paid->sendingAnonymous = _paid->scheduledAnonymous; _paid->sendingAnonymous = _paid->scheduledAnonymous;
_paid->sendingPrivacySet = _paid->scheduledPrivacySet;
_paid->scheduled = 0; _paid->scheduled = 0;
_paid->scheduledFlag = 0; _paid->scheduledFlag = 0;
_paid->scheduledAnonymous = 0; _paid->scheduledAnonymous = 0;
_paid->scheduledPrivacySet = 0;
return { return {
.count = int(_paid->sending), .count = int(_paid->sending),
.valid = true, .valid = true,
.anonymous = (_paid->sendingAnonymous == 1), .anonymous = MaybeAnonymous(
_paid->sendingPrivacySet,
_paid->sendingAnonymous),
}; };
} }
@ -2250,11 +2270,14 @@ void MessageReactions::finishPaidSending(
Expects(_paid != nullptr); Expects(_paid != nullptr);
Expects(send.count == _paid->sending); Expects(send.count == _paid->sending);
Expects(send.valid == (_paid->sendingFlag == 1)); Expects(send.valid == (_paid->sendingFlag == 1));
Expects(send.anonymous == (_paid->sendingAnonymous == 1)); Expects(send.anonymous == MaybeAnonymous(
_paid->sendingPrivacySet,
_paid->sendingAnonymous));
_paid->sending = 0; _paid->sending = 0;
_paid->sendingFlag = 0; _paid->sendingFlag = 0;
_paid->sendingAnonymous = 0; _paid->sendingAnonymous = 0;
_paid->sendingPrivacySet = 0;
if (!_paid->scheduledFlag && _paid->top.empty()) { if (!_paid->scheduledFlag && _paid->top.empty()) {
_paid = nullptr; _paid = nullptr;
} else if (!send.count) { } else if (!send.count) {
@ -2292,12 +2315,13 @@ bool MessageReactions::localPaidAnonymous() const {
return !entry.peer; return !entry.peer;
} }
} }
return false; const auto api = &_item->history()->session().api();
return api->globalPrivacy().paidReactionAnonymousCurrent();
}; };
return _paid return _paid
&& (_paid->scheduledFlag && ((_paid->scheduledFlag && _paid->scheduledPrivacySet)
? (_paid->scheduledAnonymous == 1) ? (_paid->scheduledAnonymous == 1)
: _paid->sendingFlag : (_paid->sendingFlag && _paid->sendingPrivacySet)
? (_paid->sendingAnonymous == 1) ? (_paid->sendingAnonymous == 1)
: minePaidAnonymous()); : minePaidAnonymous());
} }

View file

@ -71,7 +71,7 @@ struct MyTagInfo {
struct PaidReactionSend { struct PaidReactionSend {
int count = 0; int count = 0;
bool valid = false; bool valid = false;
bool anonymous = false; std::optional<bool> anonymous = false;
}; };
class Reactions final : private CustomEmojiManager::Listener { class Reactions final : private CustomEmojiManager::Listener {
@ -409,7 +409,7 @@ public:
[[nodiscard]] bool hasUnread() const; [[nodiscard]] bool hasUnread() const;
void markRead(); void markRead();
void scheduleSendPaid(int count, bool anonymous); void scheduleSendPaid(int count, std::optional<bool> anonymous);
[[nodiscard]] int scheduledPaid() const; [[nodiscard]] int scheduledPaid() const;
void cancelScheduledPaid(); void cancelScheduledPaid();
@ -424,12 +424,14 @@ public:
private: private:
struct Paid { struct Paid {
std::vector<TopPaid> top; std::vector<TopPaid> top;
uint32 scheduled: 30 = 0; uint32 scheduled: 29 = 0;
uint32 scheduledFlag : 1 = 0; uint32 scheduledFlag : 1 = 0;
uint32 scheduledAnonymous : 1 = 0; uint32 scheduledAnonymous : 1 = 0;
uint32 sending : 30 = 0; uint32 scheduledPrivacySet : 1 = 0;
uint32 sending : 29 = 0;
uint32 sendingFlag : 1 = 0; uint32 sendingFlag : 1 = 0;
uint32 sendingAnonymous : 1 = 0; uint32 sendingAnonymous : 1 = 0;
uint32 sendingPrivacySet : 1 = 0;
}; };
const not_null<HistoryItem*> _item; const not_null<HistoryItem*> _item;

View file

@ -2526,7 +2526,7 @@ bool HistoryItem::canReact() const {
return true; return true;
} }
void HistoryItem::addPaidReaction(int count, bool anonymous) { void HistoryItem::addPaidReaction(int count, std::optional<bool> anonymous) {
Expects(count >= 0); Expects(count >= 0);
Expects(_history->peer->isBroadcast() || isDiscussionPost()); Expects(_history->peer->isBroadcast() || isDiscussionPost());
@ -2653,9 +2653,11 @@ auto HistoryItem::topPaidReactionsWithLocal() const
const auto i = ranges::find_if( const auto i = ranges::find_if(
result, result,
[](const TopPaid &entry) { return entry.my != 0; }); [](const TopPaid &entry) { return entry.my != 0; });
const auto peer = _reactions->localPaidAnonymous() const auto peerForMine = [&] {
? nullptr return _reactions->localPaidAnonymous()
: history()->session().user().get(); ? nullptr
: history()->session().user().get();
};
if (const auto local = _reactions->localPaidCount()) { if (const auto local = _reactions->localPaidCount()) {
const auto top = [&](int mine) { const auto top = [&](int mine) {
return ranges::count_if(result, [&](const TopPaid &entry) { return ranges::count_if(result, [&](const TopPaid &entry) {
@ -2664,18 +2666,18 @@ auto HistoryItem::topPaidReactionsWithLocal() const
}; };
if (i != end(result)) { if (i != end(result)) {
i->count += local; i->count += local;
i->peer = peer; i->peer = peerForMine();
i->top = top(i->count) ? 1 : 0; i->top = top(i->count) ? 1 : 0;
} else { } else {
result.push_back({ result.push_back({
.peer = peer, .peer = peerForMine(),
.count = uint32(local), .count = uint32(local),
.top = uint32(top(local) ? 1 : 0), .top = uint32(top(local) ? 1 : 0),
.my = uint32(1), .my = uint32(1),
}); });
} }
} else if (i != end(result)) { } else if (i != end(result)) {
i->peer = peer; i->peer = peerForMine();
} }
return result; return result;
} }

View file

@ -449,7 +449,7 @@ public:
void toggleReaction( void toggleReaction(
const Data::ReactionId &reaction, const Data::ReactionId &reaction,
HistoryReactionSource source); HistoryReactionSource source);
void addPaidReaction(int count, bool anonymous); void addPaidReaction(int count, std::optional<bool> anonymous = {});
void cancelScheduledPaidReaction(); void cancelScheduledPaidReaction();
[[nodiscard]] Data::PaidReactionSend startPaidReactionSending(); [[nodiscard]] Data::PaidReactionSend startPaidReactionSending();
void finishPaidReactionSending( void finishPaidReactionSending(

View file

@ -3377,7 +3377,7 @@ void Message::refreshReactions() {
item, item,
weak.get(), weak.get(),
1, 1,
Payments::LookupMyPaidAnonymous(item), std::nullopt,
controller->uiShow()); controller->uiShow());
return; return;
} else { } else {

View file

@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/payments_reaction_process.h" #include "payments/payments_reaction_process.h"
#include "api/api_credits.h" #include "api/api_credits.h"
#include "api/api_global_privacy.h"
#include "apiwrap.h"
#include "boxes/send_credits_box.h" // CreditsEmojiSmall. #include "boxes/send_credits_box.h" // CreditsEmojiSmall.
#include "core/ui_integration.h" // MarkedTextContext. #include "core/ui_integration.h" // MarkedTextContext.
#include "data/components/credits.h" #include "data/components/credits.h"
@ -43,7 +45,7 @@ void TryAddingPaidReaction(
FullMsgId itemId, FullMsgId itemId,
base::weak_ptr<HistoryView::Element> weakView, base::weak_ptr<HistoryView::Element> weakView,
int count, int count,
bool anonymous, std::optional<bool> anonymous,
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
Fn<void(bool)> finished) { Fn<void(bool)> finished) {
const auto checkItem = [=] { const auto checkItem = [=] {
@ -103,7 +105,7 @@ void TryAddingPaidReaction(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
HistoryView::Element *view, HistoryView::Element *view,
int count, int count,
bool anonymous, std::optional<bool> anonymous,
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
Fn<void(bool)> finished) { Fn<void(bool)> finished) {
TryAddingPaidReaction( TryAddingPaidReaction(
@ -228,6 +230,9 @@ void ShowPaidReactionDetails(
add(entry); add(entry);
entry.peer = nullptr; entry.peer = nullptr;
add(entry); add(entry);
if (session->api().globalPrivacy().paidReactionAnonymousCurrent()) {
std::swap(top.front(), top.back());
}
} }
ranges::sort(top, ranges::greater(), &Ui::PaidReactionTop::count); ranges::sort(top, ranges::greater(), &Ui::PaidReactionTop::count);

View file

@ -31,7 +31,7 @@ void TryAddingPaidReaction(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
HistoryView::Element *view, HistoryView::Element *view,
int count, int count,
bool anonymous, std::optional<bool> anonymous,
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
Fn<void(bool)> finished = nullptr); Fn<void(bool)> finished = nullptr);