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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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