Prepare code for paid reactions from channels.

This commit is contained in:
John Preston 2025-02-03 12:31:05 +04:00
parent 6cb9264864
commit 79ce24222a
8 changed files with 90 additions and 69 deletions

View file

@ -154,8 +154,23 @@ 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) { [[nodiscard]] std::optional<PeerId> MaybeShownPeer(
return privacySet ? (anonymous == 1) : std::optional<bool>(); uint32 privacySet,
PeerId shownPeer) {
return privacySet ? shownPeer : std::optional<PeerId>();
}
[[nodiscard]] MTPPaidReactionPrivacy PaidReactionShownPeerToTL(
not_null<Main::Session*> session,
std::optional<PeerId> shownPeer) {
return !shownPeer
? MTPPaidReactionPrivacy()
: !*shownPeer
? MTP_paidReactionPrivacyAnonymous()
: (*shownPeer == session->userPeerId())
? MTP_paidReactionPrivacyDefault()
: MTP_paidReactionPrivacyPeer(
session->data().peer(*shownPeer)->input);
} }
} // namespace } // namespace
@ -1750,7 +1765,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.shownPeer.has_value());
Expects(!send.count); Expects(!send.count);
const auto id = item->fullId(); const auto id = item->fullId();
@ -1759,7 +1774,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)) PaidReactionShownPeerToTL(&_owner->session(), send.shownPeer))
).done([=] { ).done([=] {
if (const auto item = _owner->message(id)) { if (const auto item = _owner->message(id)) {
if (_sendingPaid.remove(item)) { if (_sendingPaid.remove(item)) {
@ -1793,12 +1808,14 @@ 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(send.anonymous ? Flag::f_private : Flag()), MTP_flags(send.shownPeer ? 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.value_or(false)) (!send.shownPeer
? MTPPaidReactionPrivacy()
: PaidReactionShownPeerToTL(&_owner->session(), *send.shownPeer))
)).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)) {
@ -1849,9 +1866,9 @@ MessageReactions::~MessageReactions() {
finishPaidSending({ finishPaidSending({
.count = int(paid->sending), .count = int(paid->sending),
.valid = true, .valid = true,
.anonymous = MaybeAnonymous( .shownPeer = MaybeShownPeer(
paid->sendingPrivacySet, paid->sendingPrivacySet,
paid->sendingAnonymous), paid->sendingShownPeer),
}, false); }, false);
} }
} }
@ -2215,7 +2232,7 @@ void MessageReactions::markRead() {
void MessageReactions::scheduleSendPaid( void MessageReactions::scheduleSendPaid(
int count, int count,
std::optional<bool> anonymous) { std::optional<PeerId> shownPeer) {
Expects(count >= 0); Expects(count >= 0);
if (!_paid) { if (!_paid) {
@ -2223,9 +2240,9 @@ void MessageReactions::scheduleSendPaid(
} }
_paid->scheduled += count; _paid->scheduled += count;
_paid->scheduledFlag = 1; _paid->scheduledFlag = 1;
if (anonymous.has_value()) { if (shownPeer.has_value()) {
_paid->scheduledAnonymous = anonymous.value_or(false) ? 1 : 0; _paid->scheduledShownPeer = *shownPeer;
_paid->scheduledPrivacySet = anonymous.has_value(); _paid->scheduledPrivacySet = true;
} }
if (count > 0) { if (count > 0) {
_item->history()->session().credits().lock(StarsAmount(count)); _item->history()->session().credits().lock(StarsAmount(count));
@ -2246,7 +2263,7 @@ void MessageReactions::cancelScheduledPaid() {
} }
_paid->scheduled = 0; _paid->scheduled = 0;
_paid->scheduledFlag = 0; _paid->scheduledFlag = 0;
_paid->scheduledAnonymous = 0; _paid->scheduledShownPeer = 0;
_paid->scheduledPrivacySet = 0; _paid->scheduledPrivacySet = 0;
} }
if (!_paid->sendingFlag && _paid->top.empty()) { if (!_paid->sendingFlag && _paid->top.empty()) {
@ -2261,18 +2278,18 @@ PaidReactionSend MessageReactions::startPaidSending() {
} }
_paid->sending = _paid->scheduled; _paid->sending = _paid->scheduled;
_paid->sendingFlag = _paid->scheduledFlag; _paid->sendingFlag = _paid->scheduledFlag;
_paid->sendingAnonymous = _paid->scheduledAnonymous; _paid->sendingShownPeer = _paid->scheduledShownPeer;
_paid->sendingPrivacySet = _paid->scheduledPrivacySet; _paid->sendingPrivacySet = _paid->scheduledPrivacySet;
_paid->scheduled = 0; _paid->scheduled = 0;
_paid->scheduledFlag = 0; _paid->scheduledFlag = 0;
_paid->scheduledAnonymous = 0; _paid->scheduledShownPeer = 0;
_paid->scheduledPrivacySet = 0; _paid->scheduledPrivacySet = 0;
return { return {
.count = int(_paid->sending), .count = int(_paid->sending),
.valid = true, .valid = true,
.anonymous = MaybeAnonymous( .shownPeer = MaybeShownPeer(
_paid->sendingPrivacySet, _paid->sendingPrivacySet,
_paid->sendingAnonymous), _paid->sendingShownPeer),
}; };
} }
@ -2282,13 +2299,13 @@ 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 == MaybeAnonymous( Expects(send.shownPeer == MaybeShownPeer(
_paid->sendingPrivacySet, _paid->sendingPrivacySet,
_paid->sendingAnonymous)); _paid->sendingShownPeer));
_paid->sending = 0; _paid->sending = 0;
_paid->sendingFlag = 0; _paid->sendingFlag = 0;
_paid->sendingAnonymous = 0; _paid->sendingShownPeer = 0;
_paid->sendingPrivacySet = 0; _paid->sendingPrivacySet = 0;
if (!_paid->scheduledFlag && _paid->top.empty()) { if (!_paid->scheduledFlag && _paid->top.empty()) {
_paid = nullptr; _paid = nullptr;
@ -2297,9 +2314,9 @@ void MessageReactions::finishPaidSending(
return top.my; return top.my;
}); });
if (i != end(_paid->top)) { if (i != end(_paid->top)) {
i->peer = send.anonymous i->peer = send.shownPeer
? nullptr ? _item->history()->owner().peer(*send.shownPeer).get()
: _item->history()->session().user().get(); : nullptr;
} }
} }
if (const auto amount = send.count) { if (const auto amount = send.count) {
@ -2320,22 +2337,23 @@ int MessageReactions::localPaidCount() const {
return _paid ? (_paid->scheduled + _paid->sending) : 0; return _paid ? (_paid->scheduled + _paid->sending) : 0;
} }
bool MessageReactions::localPaidAnonymous() const { PeerId MessageReactions::localPaidShownPeer() const {
const auto minePaidAnonymous = [&] { const auto minePaidShownPeer = [&] {
for (const auto &entry : _paid->top) { for (const auto &entry : _paid->top) {
if (entry.my) { if (entry.my) {
return !entry.peer; return entry.peer ? entry.peer->id : PeerId();
} }
} }
const auto api = &_item->history()->session().api(); const auto api = &_item->history()->session().api();
return api->globalPrivacy().paidReactionShownPeerCurrent() != 0; return api->globalPrivacy().paidReactionShownPeerCurrent();
}; };
return _paid return !_paid
&& ((_paid->scheduledFlag && _paid->scheduledPrivacySet) ? PeerId()
? (_paid->scheduledAnonymous == 1) : (_paid->scheduledFlag && _paid->scheduledPrivacySet)
: (_paid->sendingFlag && _paid->sendingPrivacySet) ? _paid->scheduledShownPeer
? (_paid->sendingAnonymous == 1) : (_paid->sendingFlag && _paid->sendingPrivacySet)
: minePaidAnonymous()); ? _paid->sendingShownPeer
: minePaidShownPeer();
} }
bool MessageReactions::clearCloudData() { bool MessageReactions::clearCloudData() {

View file

@ -71,7 +71,7 @@ struct MyTagInfo {
struct PaidReactionSend { struct PaidReactionSend {
int count = 0; int count = 0;
bool valid = false; bool valid = false;
std::optional<bool> anonymous = false; std::optional<PeerId> shownPeer = PeerId();
}; };
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, std::optional<bool> anonymous); void scheduleSendPaid(int count, std::optional<PeerId> shownPeer);
[[nodiscard]] int scheduledPaid() const; [[nodiscard]] int scheduledPaid() const;
void cancelScheduledPaid(); void cancelScheduledPaid();
@ -418,19 +418,19 @@ public:
[[nodiscard]] bool localPaidData() const; [[nodiscard]] bool localPaidData() const;
[[nodiscard]] int localPaidCount() const; [[nodiscard]] int localPaidCount() const;
[[nodiscard]] bool localPaidAnonymous() const; [[nodiscard]] PeerId localPaidShownPeer() const;
bool clearCloudData(); bool clearCloudData();
private: private:
struct Paid { struct Paid {
std::vector<TopPaid> top; std::vector<TopPaid> top;
uint32 scheduled: 29 = 0; PeerId scheduledShownPeer = 0;
PeerId sendingShownPeer = 0;
uint32 scheduled: 30 = 0;
uint32 scheduledFlag : 1 = 0; uint32 scheduledFlag : 1 = 0;
uint32 scheduledAnonymous : 1 = 0;
uint32 scheduledPrivacySet : 1 = 0; uint32 scheduledPrivacySet : 1 = 0;
uint32 sending : 29 = 0; uint32 sending : 30 = 0;
uint32 sendingFlag : 1 = 0; uint32 sendingFlag : 1 = 0;
uint32 sendingAnonymous : 1 = 0;
uint32 sendingPrivacySet : 1 = 0; uint32 sendingPrivacySet : 1 = 0;
}; };
const not_null<HistoryItem*> _item; const not_null<HistoryItem*> _item;

View file

@ -2608,14 +2608,16 @@ bool HistoryItem::canReact() const {
return true; return true;
} }
void HistoryItem::addPaidReaction(int count, std::optional<bool> anonymous) { void HistoryItem::addPaidReaction(
int count,
std::optional<PeerId> shownPeer) {
Expects(count >= 0); Expects(count >= 0);
Expects(_history->peer->isBroadcast() || isDiscussionPost()); Expects(_history->peer->isBroadcast() || isDiscussionPost());
if (!_reactions) { if (!_reactions) {
_reactions = std::make_unique<Data::MessageReactions>(this); _reactions = std::make_unique<Data::MessageReactions>(this);
} }
_reactions->scheduleSendPaid(count, anonymous); _reactions->scheduleSendPaid(count, shownPeer);
if (count > 0) { if (count > 0) {
_history->owner().notifyItemDataChange(this); _history->owner().notifyItemDataChange(this);
} }
@ -2711,8 +2713,10 @@ int HistoryItem::reactionsPaidScheduled() const {
return _reactions ? _reactions->scheduledPaid() : 0; return _reactions ? _reactions->scheduledPaid() : 0;
} }
bool HistoryItem::reactionsLocalAnonymous() const { PeerId HistoryItem::reactionsLocalShownPeer() const {
return _reactions ? _reactions->localPaidAnonymous() : false; return _reactions
? _reactions->localPaidShownPeer()
: _history->session().userPeerId();
} }
bool HistoryItem::reactionsAreTags() const { bool HistoryItem::reactionsAreTags() const {
@ -2740,9 +2744,8 @@ auto HistoryItem::topPaidReactionsWithLocal() const
result, result,
[](const TopPaid &entry) { return entry.my != 0; }); [](const TopPaid &entry) { return entry.my != 0; });
const auto peerForMine = [&] { const auto peerForMine = [&] {
return _reactions->localPaidAnonymous() const auto peerId = _reactions->localPaidShownPeer();
? nullptr return peerId ? history()->owner().peer(peerId).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) {

View file

@ -454,7 +454,7 @@ public:
void toggleReaction( void toggleReaction(
const Data::ReactionId &reaction, const Data::ReactionId &reaction,
HistoryReactionSource source); HistoryReactionSource source);
void addPaidReaction(int count, std::optional<bool> anonymous = {}); void addPaidReaction(int count, std::optional<PeerId> shownPeer = {});
void cancelScheduledPaidReaction(); void cancelScheduledPaidReaction();
[[nodiscard]] Data::PaidReactionSend startPaidReactionSending(); [[nodiscard]] Data::PaidReactionSend startPaidReactionSending();
void finishPaidReactionSending( void finishPaidReactionSending(
@ -472,7 +472,7 @@ public:
[[nodiscard]] auto topPaidReactionsWithLocal() const [[nodiscard]] auto topPaidReactionsWithLocal() const
-> std::vector<Data::MessageReactionsTopPaid>; -> std::vector<Data::MessageReactionsTopPaid>;
[[nodiscard]] int reactionsPaidScheduled() const; [[nodiscard]] int reactionsPaidScheduled() const;
[[nodiscard]] bool reactionsLocalAnonymous() const; [[nodiscard]] PeerId reactionsLocalShownPeer() const;
[[nodiscard]] bool canViewReactions() const; [[nodiscard]] bool canViewReactions() const;
[[nodiscard]] std::vector<Data::ReactionId> chosenReactions() const; [[nodiscard]] std::vector<Data::ReactionId> chosenReactions() const;
[[nodiscard]] Data::ReactionId lookupUnreadReaction( [[nodiscard]] Data::ReactionId lookupUnreadReaction(

View file

@ -163,7 +163,7 @@ PaidReactionToast::~PaidReactionToast() {
bool PaidReactionToast::maybeShowFor(not_null<HistoryItem*> item) { bool PaidReactionToast::maybeShowFor(not_null<HistoryItem*> item) {
const auto count = item->reactionsPaidScheduled(); const auto count = item->reactionsPaidScheduled();
const auto anonymous = item->reactionsLocalAnonymous(); const auto shownPeer = item->reactionsLocalShownPeer();
const auto at = _owner->reactions().sendingScheduledPaidAt(item); const auto at = _owner->reactions().sendingScheduledPaidAt(item);
if (!count || !at) { if (!count || !at) {
return false; return false;
@ -173,14 +173,14 @@ bool PaidReactionToast::maybeShowFor(not_null<HistoryItem*> item) {
if (at <= crl::now() + ignore) { if (at <= crl::now() + ignore) {
return false; return false;
} }
showFor(item->fullId(), count, anonymous, at - ignore, total); showFor(item->fullId(), count, shownPeer, at - ignore, total);
return true; return true;
} }
void PaidReactionToast::showFor( void PaidReactionToast::showFor(
FullMsgId itemId, FullMsgId itemId,
int count, int count,
bool anonymous, PeerId shownPeer,
crl::time finish, crl::time finish,
crl::time total) { crl::time total) {
const auto old = _weak.get(); const auto old = _weak.get();
@ -188,7 +188,7 @@ void PaidReactionToast::showFor(
if (i != end(_stack)) { if (i != end(_stack)) {
if (old && i + 1 == end(_stack)) { if (old && i + 1 == end(_stack)) {
_count = count; _count = count;
_anonymous = anonymous; _shownPeer = shownPeer;
_timeFinish = finish; _timeFinish = finish;
return; return;
} }
@ -202,14 +202,14 @@ void PaidReactionToast::showFor(
_hiding.push_back(base::take(_weak)); _hiding.push_back(base::take(_weak));
} }
_count.reset(); _count.reset();
_anonymous.reset(); _shownPeer.reset();
_timeFinish.reset(); _timeFinish.reset();
_count = count; _count = count;
_anonymous = anonymous; _shownPeer = shownPeer;
_timeFinish = finish; _timeFinish = finish;
auto text = rpl::combine( auto text = rpl::combine(
rpl::conditional( rpl::conditional(
_anonymous.value(), _shownPeer.value() | rpl::map(rpl::mappers::_1 == PeerId()),
tr::lng_paid_react_toast_anonymous( tr::lng_paid_react_toast_anonymous(
lt_count, lt_count,
_count.value() | tr::to_count(), _count.value() | tr::to_count(),

View file

@ -40,7 +40,7 @@ private:
void showFor( void showFor(
FullMsgId itemId, FullMsgId itemId,
int count, int count,
bool anonymous, PeerId shownPeer,
crl::time left, crl::time left,
crl::time total); crl::time total);
@ -54,7 +54,7 @@ private:
base::weak_ptr<Ui::Toast::Instance> _weak; base::weak_ptr<Ui::Toast::Instance> _weak;
std::vector<base::weak_ptr<Ui::Toast::Instance>> _hiding; std::vector<base::weak_ptr<Ui::Toast::Instance>> _hiding;
rpl::variable<int> _count; rpl::variable<int> _count;
rpl::variable<bool> _anonymous; rpl::variable<PeerId> _shownPeer;
rpl::variable<crl::time> _timeFinish; rpl::variable<crl::time> _timeFinish;
std::vector<FullMsgId> _stack; std::vector<FullMsgId> _stack;

View file

@ -45,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,
std::optional<bool> anonymous, std::optional<PeerId> shownPeer,
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 = [=] {
@ -66,7 +66,7 @@ void TryAddingPaidReaction(
if (result == Settings::SmallBalanceResult::Success if (result == Settings::SmallBalanceResult::Success
|| result == Settings::SmallBalanceResult::Already) { || result == Settings::SmallBalanceResult::Already) {
if (const auto item = checkItem()) { if (const auto item = checkItem()) {
item->addPaidReaction(count, anonymous); item->addPaidReaction(count, shownPeer);
if (const auto view = count ? weakView.get() : nullptr) { if (const auto view = count ? weakView.get() : nullptr) {
const auto history = view->history(); const auto history = view->history();
history->owner().notifyViewPaidReactionSent(view); history->owner().notifyViewPaidReactionSent(view);
@ -105,7 +105,7 @@ void TryAddingPaidReaction(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
HistoryView::Element *view, HistoryView::Element *view,
int count, int count,
std::optional<bool> anonymous, std::optional<PeerId> shownPeer,
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
Fn<void(bool)> finished) { Fn<void(bool)> finished) {
TryAddingPaidReaction( TryAddingPaidReaction(
@ -113,7 +113,7 @@ void TryAddingPaidReaction(
item->fullId(), item->fullId(),
view, view,
count, count,
anonymous, shownPeer,
std::move(show), std::move(show),
std::move(finished)); std::move(finished));
} }
@ -140,26 +140,26 @@ void ShowPaidReactionDetails(
struct State { struct State {
QPointer<Ui::BoxContent> selectBox; QPointer<Ui::BoxContent> selectBox;
bool ignoreAnonymousSwitch = false; bool ignoreShownPeerSwitch = false;
bool sending = false; bool sending = false;
}; };
const auto state = std::make_shared<State>(); const auto state = std::make_shared<State>();
session->credits().load(true); session->credits().load(true);
const auto weakView = base::make_weak(view); const auto weakView = base::make_weak(view);
const auto send = [=](int count, bool anonymous, auto resend) -> void { const auto send = [=](int count, PeerId shownPeer, auto resend) -> void {
Expects(count >= 0); Expects(count >= 0);
const auto finish = [=](bool success) { const auto finish = [=](bool success) {
state->sending = false; state->sending = false;
if (success && count > 0) { if (success && count > 0) {
state->ignoreAnonymousSwitch = true; state->ignoreShownPeerSwitch = true;
if (const auto strong = state->selectBox.data()) { if (const auto strong = state->selectBox.data()) {
strong->closeBox(); strong->closeBox();
} }
} }
}; };
if (state->sending || (!count && state->ignoreAnonymousSwitch)) { if (state->sending || (!count && state->ignoreShownPeerSwitch)) {
return; return;
} else if (const auto item = session->data().message(itemId)) { } else if (const auto item = session->data().message(itemId)) {
state->sending = true; state->sending = true;
@ -167,7 +167,7 @@ void ShowPaidReactionDetails(
item, item,
weakView.get(), weakView.get(),
count, count,
anonymous, shownPeer,
show, show,
finish); finish);
} }
@ -246,7 +246,7 @@ void ShowPaidReactionDetails(
.submit = std::move(submitText), .submit = std::move(submitText),
.balanceValue = session->credits().balanceValue(), .balanceValue = session->credits().balanceValue(),
.send = [=](int count, bool anonymous) { .send = [=](int count, bool anonymous) {
send(count, anonymous, send); send(count, anonymous ? PeerId() : 0, send);
}, },
})); }));

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,
std::optional<bool> anonymous, std::optional<PeerId> shownPeer,
std::shared_ptr<Ui::Show> show, std::shared_ptr<Ui::Show> show,
Fn<void(bool)> finished = nullptr); Fn<void(bool)> finished = nullptr);