From d81547f091f24e999ec03cd74b1ddb4fa1f60db9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 30 Aug 2024 10:31:57 +0400 Subject: [PATCH] Support cloud-saved paid reaction privacy. --- .../SourceFiles/api/api_global_privacy.cpp | 22 ++++++++ Telegram/SourceFiles/api/api_global_privacy.h | 7 +++ Telegram/SourceFiles/api/api_updates.cpp | 7 +++ Telegram/SourceFiles/data/data_channel.cpp | 4 ++ .../data/data_message_reactions.cpp | 50 ++++++++++++++----- .../SourceFiles/data/data_message_reactions.h | 10 ++-- Telegram/SourceFiles/history/history_item.cpp | 16 +++--- Telegram/SourceFiles/history/history_item.h | 2 +- .../history/view/history_view_message.cpp | 2 +- .../payments/payments_reaction_process.cpp | 9 +++- .../payments/payments_reaction_process.h | 2 +- 11 files changed, 102 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/api/api_global_privacy.cpp b/Telegram/SourceFiles/api/api_global_privacy.cpp index d1beddfb62..83ad8d1565 100644 --- a/Telegram/SourceFiles/api/api_global_privacy.cpp +++ b/Telegram/SourceFiles/api/api_global_privacy.cpp @@ -115,6 +115,28 @@ rpl::producer GlobalPrivacy::newRequirePremium() const { 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 GlobalPrivacy::paidReactionAnonymous() const { + return _paidReactionAnonymous.value(); +} void GlobalPrivacy::updateArchiveAndMute(bool value) { update( diff --git a/Telegram/SourceFiles/api/api_global_privacy.h b/Telegram/SourceFiles/api/api_global_privacy.h index de70ba9b97..aa7bb28fe3 100644 --- a/Telegram/SourceFiles/api/api_global_privacy.h +++ b/Telegram/SourceFiles/api/api_global_privacy.h @@ -49,6 +49,11 @@ public: [[nodiscard]] bool newRequirePremiumCurrent() const; [[nodiscard]] rpl::producer newRequirePremium() const; + void loadPaidReactionAnonymous(); + void updatePaidReactionAnonymous(bool value); + [[nodiscard]] bool paidReactionAnonymousCurrent() const; + [[nodiscard]] rpl::producer paidReactionAnonymous() const; + private: void apply(const MTPGlobalPrivacySettings &data); @@ -67,7 +72,9 @@ private: rpl::variable _showArchiveAndMute = false; rpl::variable _hideReadTime = false; rpl::variable _newRequirePremium = false; + rpl::variable _paidReactionAnonymous = false; std::vector> _callbacks; + bool _paidReactionAnonymousLoaded = false; }; diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 3aa7479c74..25ee380f84 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_authorizations.h" #include "api/api_user_names.h" #include "api/api_chat_participants.h" +#include "api/api_global_privacy.h" #include "api/api_ringtones.h" #include "api/api_text_entities.h" #include "api/api_user_privacy.h" @@ -2622,6 +2623,12 @@ void Updates::feedUpdate(const MTPUpdate &update) { _session->credits().apply(data); } break; + case mtpc_updatePaidReactionPrivacy: { + const auto &data = update.c_updatePaidReactionPrivacy(); + _session->api().globalPrivacy().updatePaidReactionAnonymous( + mtpIsTrue(data.vprivate())); + } break; + } } diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 3a52d4c5fa..157a16b392 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_channel.h" +#include "api/api_global_privacy.h" #include "data/data_changes.h" #include "data/data_channel_admins.h" #include "data/data_user.h" @@ -971,6 +972,9 @@ PeerId ChannelData::groupCallDefaultJoinAs() const { void ChannelData::setAllowedReactions(Data::AllowedReactions value) { if (_allowedReactions != value) { + if (value.paidEnabled) { + session().api().globalPrivacy().loadPaidReactionAnonymous(); + } const auto enabled = [](const Data::AllowedReactions &allowed) { return (allowed.type != Data::AllowedReactionsType::Some) || !allowed.some.empty() diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 57261461bd..d360ccf65a 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_message_reactions.h" +#include "api/api_global_privacy.h" #include "chat_helpers/stickers_lottie.h" #include "core/application.h" #include "history/history.h" @@ -152,6 +153,10 @@ constexpr auto kPaidAccumulatePeriod = 5 * crl::time(1000) + 500; return (i != end(top)) && i->my; } +[[nodiscard]] std::optional MaybeAnonymous(uint32 privacySet, uint32 anonymous) { + return privacySet ? (anonymous == 1) : std::optional(); +} + } // namespace PossibleItemReactionsRef LookupPossibleReactions( @@ -1734,6 +1739,7 @@ void Reactions::sendPaidPrivacyRequest( not_null item, PaidReactionSend send) { Expects(!_sendingPaid.contains(item)); + Expects(send.anonymous.has_value()); Expects(!send.count); const auto id = item->fullId(); @@ -1742,7 +1748,7 @@ void Reactions::sendPaidPrivacyRequest( MTPmessages_TogglePaidReactionPrivacy( item->history()->peer->input, MTP_int(id.msg), - MTP_bool(send.anonymous)) + MTP_bool(*send.anonymous)) ).done([=] { if (const auto item = _owner->message(id)) { if (_sendingPaid.remove(item)) { @@ -1776,12 +1782,12 @@ void Reactions::sendPaidRequest( auto &api = _owner->session().api(); using Flag = MTPmessages_SendPaidReaction::Flag; const auto requestId = api.request(MTPmessages_SendPaidReaction( - MTP_flags(Flag::f_private), + MTP_flags(send.anonymous ? Flag::f_private : Flag()), item->history()->peer->input, MTP_int(id.msg), MTP_int(send.count), MTP_long(randomId), - MTP_bool(send.anonymous) + MTP_bool(send.anonymous.value_or(false)) )).done([=](const MTPUpdates &result) { if (const auto item = _owner->message(id)) { if (_sendingPaid.remove(item)) { @@ -1829,9 +1835,13 @@ MessageReactions::~MessageReactions() { cancelScheduledPaid(); if (const auto paid = _paid.get()) { if (paid->sending > 0) { - finishPaidSending( - { int(paid->sending), (paid->sendingAnonymous == 1) }, - false); + finishPaidSending({ + .count = int(paid->sending), + .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 anonymous) { Expects(count >= 0); if (!_paid) { @@ -2200,7 +2212,10 @@ void MessageReactions::scheduleSendPaid(int count, bool anonymous) { } _paid->scheduled += count; _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) { _item->history()->session().credits().lock(count); } @@ -2220,6 +2235,7 @@ void MessageReactions::cancelScheduledPaid() { _paid->scheduled = 0; _paid->scheduledFlag = 0; _paid->scheduledAnonymous = 0; + _paid->scheduledPrivacySet = 0; } if (!_paid->sendingFlag && _paid->top.empty()) { _paid = nullptr; @@ -2234,13 +2250,17 @@ PaidReactionSend MessageReactions::startPaidSending() { _paid->sending = _paid->scheduled; _paid->sendingFlag = _paid->scheduledFlag; _paid->sendingAnonymous = _paid->scheduledAnonymous; + _paid->sendingPrivacySet = _paid->scheduledPrivacySet; _paid->scheduled = 0; _paid->scheduledFlag = 0; _paid->scheduledAnonymous = 0; + _paid->scheduledPrivacySet = 0; return { .count = int(_paid->sending), .valid = true, - .anonymous = (_paid->sendingAnonymous == 1), + .anonymous = MaybeAnonymous( + _paid->sendingPrivacySet, + _paid->sendingAnonymous), }; } @@ -2250,11 +2270,14 @@ void MessageReactions::finishPaidSending( Expects(_paid != nullptr); Expects(send.count == _paid->sending); Expects(send.valid == (_paid->sendingFlag == 1)); - Expects(send.anonymous == (_paid->sendingAnonymous == 1)); + Expects(send.anonymous == MaybeAnonymous( + _paid->sendingPrivacySet, + _paid->sendingAnonymous)); _paid->sending = 0; _paid->sendingFlag = 0; _paid->sendingAnonymous = 0; + _paid->sendingPrivacySet = 0; if (!_paid->scheduledFlag && _paid->top.empty()) { _paid = nullptr; } else if (!send.count) { @@ -2292,12 +2315,13 @@ bool MessageReactions::localPaidAnonymous() const { return !entry.peer; } } - return false; + const auto api = &_item->history()->session().api(); + return api->globalPrivacy().paidReactionAnonymousCurrent(); }; return _paid - && (_paid->scheduledFlag + && ((_paid->scheduledFlag && _paid->scheduledPrivacySet) ? (_paid->scheduledAnonymous == 1) - : _paid->sendingFlag + : (_paid->sendingFlag && _paid->sendingPrivacySet) ? (_paid->sendingAnonymous == 1) : minePaidAnonymous()); } diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index 37c33047ef..f1bf36f464 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -71,7 +71,7 @@ struct MyTagInfo { struct PaidReactionSend { int count = 0; bool valid = false; - bool anonymous = false; + std::optional anonymous = false; }; class Reactions final : private CustomEmojiManager::Listener { @@ -409,7 +409,7 @@ public: [[nodiscard]] bool hasUnread() const; void markRead(); - void scheduleSendPaid(int count, bool anonymous); + void scheduleSendPaid(int count, std::optional anonymous); [[nodiscard]] int scheduledPaid() const; void cancelScheduledPaid(); @@ -424,12 +424,14 @@ public: private: struct Paid { std::vector top; - uint32 scheduled: 30 = 0; + uint32 scheduled: 29 = 0; uint32 scheduledFlag : 1 = 0; uint32 scheduledAnonymous : 1 = 0; - uint32 sending : 30 = 0; + uint32 scheduledPrivacySet : 1 = 0; + uint32 sending : 29 = 0; uint32 sendingFlag : 1 = 0; uint32 sendingAnonymous : 1 = 0; + uint32 sendingPrivacySet : 1 = 0; }; const not_null _item; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index e27f735fd0..e03d310ebb 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2526,7 +2526,7 @@ bool HistoryItem::canReact() const { return true; } -void HistoryItem::addPaidReaction(int count, bool anonymous) { +void HistoryItem::addPaidReaction(int count, std::optional anonymous) { Expects(count >= 0); Expects(_history->peer->isBroadcast() || isDiscussionPost()); @@ -2653,9 +2653,11 @@ auto HistoryItem::topPaidReactionsWithLocal() const const auto i = ranges::find_if( result, [](const TopPaid &entry) { return entry.my != 0; }); - const auto peer = _reactions->localPaidAnonymous() - ? nullptr - : history()->session().user().get(); + const auto peerForMine = [&] { + return _reactions->localPaidAnonymous() + ? nullptr + : history()->session().user().get(); + }; if (const auto local = _reactions->localPaidCount()) { const auto top = [&](int mine) { return ranges::count_if(result, [&](const TopPaid &entry) { @@ -2664,18 +2666,18 @@ auto HistoryItem::topPaidReactionsWithLocal() const }; if (i != end(result)) { i->count += local; - i->peer = peer; + i->peer = peerForMine(); i->top = top(i->count) ? 1 : 0; } else { result.push_back({ - .peer = peer, + .peer = peerForMine(), .count = uint32(local), .top = uint32(top(local) ? 1 : 0), .my = uint32(1), }); } } else if (i != end(result)) { - i->peer = peer; + i->peer = peerForMine(); } return result; } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index f3ad4b854f..bab7f4d7cb 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -449,7 +449,7 @@ public: void toggleReaction( const Data::ReactionId &reaction, HistoryReactionSource source); - void addPaidReaction(int count, bool anonymous); + void addPaidReaction(int count, std::optional anonymous = {}); void cancelScheduledPaidReaction(); [[nodiscard]] Data::PaidReactionSend startPaidReactionSending(); void finishPaidReactionSending( diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 50d47051e9..b0c8c223fb 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -3377,7 +3377,7 @@ void Message::refreshReactions() { item, weak.get(), 1, - Payments::LookupMyPaidAnonymous(item), + std::nullopt, controller->uiShow()); return; } else { diff --git a/Telegram/SourceFiles/payments/payments_reaction_process.cpp b/Telegram/SourceFiles/payments/payments_reaction_process.cpp index d66063b330..7050fa120a 100644 --- a/Telegram/SourceFiles/payments/payments_reaction_process.cpp +++ b/Telegram/SourceFiles/payments/payments_reaction_process.cpp @@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "payments/payments_reaction_process.h" #include "api/api_credits.h" +#include "api/api_global_privacy.h" +#include "apiwrap.h" #include "boxes/send_credits_box.h" // CreditsEmojiSmall. #include "core/ui_integration.h" // MarkedTextContext. #include "data/components/credits.h" @@ -43,7 +45,7 @@ void TryAddingPaidReaction( FullMsgId itemId, base::weak_ptr weakView, int count, - bool anonymous, + std::optional anonymous, std::shared_ptr show, Fn finished) { const auto checkItem = [=] { @@ -103,7 +105,7 @@ void TryAddingPaidReaction( not_null item, HistoryView::Element *view, int count, - bool anonymous, + std::optional anonymous, std::shared_ptr show, Fn finished) { TryAddingPaidReaction( @@ -228,6 +230,9 @@ void ShowPaidReactionDetails( add(entry); entry.peer = nullptr; add(entry); + if (session->api().globalPrivacy().paidReactionAnonymousCurrent()) { + std::swap(top.front(), top.back()); + } } ranges::sort(top, ranges::greater(), &Ui::PaidReactionTop::count); diff --git a/Telegram/SourceFiles/payments/payments_reaction_process.h b/Telegram/SourceFiles/payments/payments_reaction_process.h index d9e945f336..1aa5d7b5ed 100644 --- a/Telegram/SourceFiles/payments/payments_reaction_process.h +++ b/Telegram/SourceFiles/payments/payments_reaction_process.h @@ -31,7 +31,7 @@ void TryAddingPaidReaction( not_null item, HistoryView::Element *view, int count, - bool anonymous, + std::optional anonymous, std::shared_ptr show, Fn finished = nullptr);