Fixed build with layer 206.

This commit is contained in:
23rd 2025-06-27 23:45:20 +03:00
parent 140862ce5a
commit 50d74fcf25
14 changed files with 180 additions and 125 deletions

View file

@ -80,7 +80,7 @@ constexpr auto kTransactionsLimit = 100;
}, [](const auto &) { return (const MTPDstarGift*)nullptr; }) }, [](const auto &) { return (const MTPDstarGift*)nullptr; })
: nullptr; : nullptr;
const auto reaction = tl.data().is_reaction(); const auto reaction = tl.data().is_reaction();
const auto amount = CreditsAmountFromTL(tl.data().vstars()); const auto amount = CreditsAmountFromTL(tl.data().vamount());
const auto starrefAmount = CreditsAmountFromTL( const auto starrefAmount = CreditsAmountFromTL(
tl.data().vstarref_amount()); tl.data().vstarref_amount());
const auto starrefCommission const auto starrefCommission
@ -107,7 +107,7 @@ constexpr auto kTransactionsLimit = 100;
.date = base::unixtime::parse(tl.data().vdate().v), .date = base::unixtime::parse(tl.data().vdate().v),
.photoId = photo ? photo->id : 0, .photoId = photo ? photo->id : 0,
.extended = std::move(extended), .extended = std::move(extended),
.credits = CreditsAmountFromTL(tl.data().vstars()), .credits = CreditsAmountFromTL(tl.data().vamount()),
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()), .bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
.barePeerId = saveActorId ? peer->id.value : barePeerId, .barePeerId = saveActorId ? peer->id.value : barePeerId,
.bareGiveawayMsgId = uint64( .bareGiveawayMsgId = uint64(

View file

@ -56,7 +56,6 @@ void HandleWithdrawalButton(
? &currencyReceiver->session() ? &currencyReceiver->session()
: &creditsReceiver->session()); : &creditsReceiver->session());
using ChannelOutUrl = MTPstats_BroadcastRevenueWithdrawalUrl;
using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl; using CreditsOutUrl = MTPpayments_StarsRevenueWithdrawalUrl;
session->api().cloudPassword().reload(); session->api().cloudPassword().reload();
@ -98,19 +97,19 @@ void HandleWithdrawalButton(
show->showToast(message); show->showToast(message);
} }
}; };
if (currencyReceiver) { if (currencyReceiver || creditsReceiver) {
session->api().request( using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag;
MTPstats_GetBroadcastRevenueWithdrawalUrl(
currencyReceiver->input,
result.result
)).done([=](const ChannelOutUrl &r) {
done(qs(r.data().vurl()));
}).fail(fail).send();
} else if (creditsReceiver) {
session->api().request( session->api().request(
MTPpayments_GetStarsRevenueWithdrawalUrl( MTPpayments_GetStarsRevenueWithdrawalUrl(
creditsReceiver->input, MTP_flags(currencyReceiver
MTP_long(receiver.creditsAmount()), ? F::f_ton
: F::f_amount),
currencyReceiver
? currencyReceiver->input
: creditsReceiver->input,
MTP_long(creditsReceiver
? receiver.creditsAmount()
: 0),
result.result result.result
)).done([=](const CreditsOutUrl &r) { )).done([=](const CreditsOutUrl &r) {
done(qs(r.data().vurl())); done(qs(r.data().vurl()));
@ -138,17 +137,19 @@ void HandleWithdrawalButton(
processOut(); processOut();
} }
}; };
if (currencyReceiver) { if (currencyReceiver || creditsReceiver) {
session->api().request( using F = MTPpayments_getStarsRevenueWithdrawalUrl::Flag;
MTPstats_GetBroadcastRevenueWithdrawalUrl(
currencyReceiver->input,
MTP_inputCheckPasswordEmpty()
)).fail(fail).send();
} else if (creditsReceiver) {
session->api().request( session->api().request(
MTPpayments_GetStarsRevenueWithdrawalUrl( MTPpayments_GetStarsRevenueWithdrawalUrl(
creditsReceiver->input, MTP_flags(currencyReceiver
MTP_long(receiver.creditsAmount()), ? F::f_ton
: F::f_amount),
currencyReceiver
? currencyReceiver->input
: creditsReceiver->input,
MTP_long(creditsReceiver
? receiver.creditsAmount()
: 0),
MTP_inputCheckPasswordEmpty() MTP_inputCheckPasswordEmpty()
)).fail(fail).send(); )).fail(fail).send();
} }

View file

@ -695,19 +695,23 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
return [=](auto consumer) { return [=](auto consumer) {
auto lifetime = rpl::lifetime(); auto lifetime = rpl::lifetime();
makeRequest(MTPstats_GetBroadcastRevenueStats( makeRequest(MTPpayments_GetStarsRevenueStats(
MTP_flags(0), MTP_flags(MTPpayments_getStarsRevenueStats::Flag::f_ton),
(_isUser ? user()->input : channel()->input) (_isUser ? user()->input : channel()->input)
)).done([=](const MTPstats_BroadcastRevenueStats &result) { )).done([=](const MTPpayments_StarsRevenueStats &result) {
const auto &data = result.data(); const auto &data = result.data();
const auto &balances = data.vbalances().data(); const auto &balances = data.vstatus().data();
const auto amount = [](const auto &a) {
return CreditsAmountFromTL(a);
};
_data = Data::EarnStatistics{ _data = Data::EarnStatistics{
.topHoursGraph = StatisticalGraphFromTL( .topHoursGraph = data.vtop_hours_graph()
data.vtop_hours_graph()), ? StatisticalGraphFromTL(*data.vtop_hours_graph())
: Data::StatisticalGraph(),
.revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()), .revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()),
.currentBalance = balances.vcurrent_balance().v, .currentBalance = amount(balances.vcurrent_balance()),
.availableBalance = balances.vavailable_balance().v, .availableBalance = amount(balances.vavailable_balance()),
.overallRevenue = balances.voverall_revenue().v, .overallRevenue = amount(balances.voverall_revenue()),
.usdRate = data.vusd_rate().v, .usdRate = data.vusd_rate().v,
}; };
@ -745,39 +749,60 @@ void EarnStatistics::requestHistory(
if (_requestId) { if (_requestId) {
return; return;
} }
constexpr auto kTlFirstSlice = tl::make_int(kFirstSlice); constexpr auto kTlFirstSlice = tl::make_int(kFirstSlice);
constexpr auto kTlLimit = tl::make_int(kLimit); constexpr auto kTlLimit = tl::make_int(kLimit);
_requestId = api().request(MTPstats_GetBroadcastRevenueTransactions(
_requestId = api().request(MTPpayments_GetStarsTransactions(
MTP_flags(MTPpayments_getStarsTransactions::Flag::f_ton
| MTPpayments_getStarsTransactions::Flag::f_inbound
| MTPpayments_getStarsTransactions::Flag::f_outbound),
MTP_string(), // Subscription ID.
(_isUser ? user()->input : channel()->input), (_isUser ? user()->input : channel()->input),
MTP_int(token), MTP_string(token),
(!token) ? kTlFirstSlice : kTlLimit token.isEmpty() ? kTlFirstSlice : kTlLimit
)).done([=](const MTPstats_BroadcastRevenueTransactions &result) { )).done([=](const MTPpayments_StarsStatus &result) {
_requestId = 0; _requestId = 0;
const auto &tlTransactions = result.data().vtransactions().v; const auto nextToken = result.data().vnext_offset().value_or_empty();
qDebug() << "next" << nextToken;
const auto &tlTransactions
= result.data().vhistory().value_or_empty();
auto list = std::vector<Data::EarnHistoryEntry>(); auto list = std::vector<Data::EarnHistoryEntry>();
list.reserve(tlTransactions.size()); list.reserve(tlTransactions.size());
for (const auto &tlTransaction : tlTransactions) { for (const auto &tlTransaction : tlTransactions) {
list.push_back(tlTransaction.match([&]( const auto &d = tlTransaction.data();
const MTPDbroadcastRevenueTransactionProceeds &d) { const auto isProceed = d.vads_proceeds_from_date()
return Data::EarnHistoryEntry{ || d.vads_proceeds_to_date();
const auto isRefund = d.is_refund();
const auto amount = CreditsAmountFromTL(d.vamount());
if (isProceed) {
list.push_back(Data::EarnHistoryEntry{
.type = Data::EarnHistoryEntry::Type::In, .type = Data::EarnHistoryEntry::Type::In,
.amount = d.vamount().v, .amount = amount,
.date = base::unixtime::parse(d.vfrom_date().v), .date = base::unixtime::parse(
.dateTo = base::unixtime::parse(d.vto_date().v), d.vads_proceeds_from_date()->v),
}; .dateTo = base::unixtime::parse(
}, [&](const MTPDbroadcastRevenueTransactionWithdrawal &d) { d.vads_proceeds_to_date()->v),
return Data::EarnHistoryEntry{ });
} else if (isRefund) {
list.push_back(Data::EarnHistoryEntry{
.type = Data::EarnHistoryEntry::Type::Return,
.amount = amount,
.date = base::unixtime::parse(d.vdate().v),
// .provider = qs(d.vprovider()),
});
} else {
list.push_back(Data::EarnHistoryEntry{
.type = Data::EarnHistoryEntry::Type::Out, .type = Data::EarnHistoryEntry::Type::Out,
.status = d.is_pending() .status = d.is_pending()
? Data::EarnHistoryEntry::Status::Pending ? Data::EarnHistoryEntry::Status::Pending
: d.is_failed() : d.is_failed()
? Data::EarnHistoryEntry::Status::Failed ? Data::EarnHistoryEntry::Status::Failed
: Data::EarnHistoryEntry::Status::Success, : Data::EarnHistoryEntry::Status::Success,
.amount = (std::numeric_limits<Data::EarnInt>::max() .amount = amount,
- d.vamount().v
+ 1),
.date = base::unixtime::parse(d.vdate().v), .date = base::unixtime::parse(d.vdate().v),
// .provider = qs(d.vprovider()), // .provider = qs(d.vprovider()),
.successDate = d.vtransaction_date() .successDate = d.vtransaction_date()
@ -786,21 +811,14 @@ void EarnStatistics::requestHistory(
.successLink = d.vtransaction_url() .successLink = d.vtransaction_url()
? qs(*d.vtransaction_url()) ? qs(*d.vtransaction_url())
: QString(), : QString(),
}; });
}, [&](const MTPDbroadcastRevenueTransactionRefund &d) { }
return Data::EarnHistoryEntry{
.type = Data::EarnHistoryEntry::Type::Return,
.amount = d.vamount().v,
.date = base::unixtime::parse(d.vdate().v),
// .provider = qs(d.vprovider()),
};
}));
} }
const auto nextToken = token + tlTransactions.size();
done(Data::EarnHistorySlice{ done(Data::EarnHistorySlice{
.list = std::move(list), .list = std::move(list),
.total = result.data().vcount().v, .total = int(tlTransactions.size()),
.allLoaded = (result.data().vcount().v == nextToken), // .total = result.data().vcount().v,
.allLoaded = nextToken.isEmpty(),
.token = Data::EarnHistorySlice::OffsetToken(nextToken), .token = Data::EarnHistorySlice::OffsetToken(nextToken),
}); });
}).fail([=] { }).fail([=] {

View file

@ -1841,9 +1841,8 @@ void Controller::fillBotCurrencyButton() {
auto &lifetime = _controls.buttonsLayout->lifetime(); auto &lifetime = _controls.buttonsLayout->lifetime();
const auto state = lifetime.make_state<State>(); const auto state = lifetime.make_state<State>();
const auto format = [=](uint64 balance) { const auto format = [=](const CreditsAmount &balance) {
return Info::ChannelEarn::MajorPart(balance) return Lang::FormatCreditsAmountDecimal(balance);
+ Info::ChannelEarn::MinorPart(balance);
}; };
const auto was = _peer->session().credits().balanceCurrency( const auto was = _peer->session().credits().balanceCurrency(
_peer->id); _peer->id);

View file

@ -85,9 +85,11 @@ CreditsAmount Credits::balance(PeerId peerId) const {
return (it != _cachedPeerBalances.end()) ? it->second : CreditsAmount(); return (it != _cachedPeerBalances.end()) ? it->second : CreditsAmount();
} }
uint64 Credits::balanceCurrency(PeerId peerId) const { CreditsAmount Credits::balanceCurrency(PeerId peerId) const {
const auto it = _cachedPeerCurrencyBalances.find(peerId); const auto it = _cachedPeerCurrencyBalances.find(peerId);
return (it != _cachedPeerCurrencyBalances.end()) ? it->second : 0; return (it != _cachedPeerCurrencyBalances.end())
? it->second
: CreditsAmount();
} }
rpl::producer<CreditsAmount> Credits::balanceValue() const { rpl::producer<CreditsAmount> Credits::balanceValue() const {
@ -204,7 +206,7 @@ void Credits::apply(PeerId peerId, CreditsAmount balance) {
_refreshedByPeerId.fire_copy(peerId); _refreshedByPeerId.fire_copy(peerId);
} }
void Credits::applyCurrency(PeerId peerId, uint64 balance) { void Credits::applyCurrency(PeerId peerId, CreditsAmount balance) {
_cachedPeerCurrencyBalances[peerId] = balance; _cachedPeerCurrencyBalances[peerId] = balance;
_refreshedByPeerId.fire_copy(peerId); _refreshedByPeerId.fire_copy(peerId);
} }
@ -227,10 +229,17 @@ CreditsAmount CreditsAmountFromTL(const MTPStarsAmount &amount) {
data.vnanos().v, data.vnanos().v,
CreditsType::Stars); CreditsType::Stars);
}, [&](const MTPDstarsTonAmount &data) { }, [&](const MTPDstarsTonAmount &data) {
return CreditsAmount( const auto isNegative = (static_cast<int64_t>(data.vamount().v) < 0);
data.vamount().v / uint64(1'000'000'000), const auto absValue = isNegative
data.vamount().v % uint64(1'000'000'000), ? uint64(~data.vamount().v + 1)
: data.vamount().v;
const auto result = CreditsAmount(
int64(absValue / 1'000'000'000),
absValue % 1'000'000'000,
CreditsType::Ton); CreditsType::Ton);
return isNegative
? CreditsAmount(0, CreditsType::Ton) - result
: result;
}); });
} }

View file

@ -40,8 +40,8 @@ public:
[[nodiscard]] bool statsEnabled() const; [[nodiscard]] bool statsEnabled() const;
void applyCurrency(PeerId peerId, uint64 balance); void applyCurrency(PeerId peerId, CreditsAmount balance);
[[nodiscard]] uint64 balanceCurrency(PeerId peerId) const; [[nodiscard]] CreditsAmount balanceCurrency(PeerId peerId) const;
void lock(CreditsAmount count); void lock(CreditsAmount count);
void unlock(CreditsAmount count); void unlock(CreditsAmount count);
@ -58,7 +58,7 @@ private:
std::unique_ptr<rpl::lifetime> _loader; std::unique_ptr<rpl::lifetime> _loader;
base::flat_map<PeerId, CreditsAmount> _cachedPeerBalances; base::flat_map<PeerId, CreditsAmount> _cachedPeerBalances;
base::flat_map<PeerId, uint64> _cachedPeerCurrencyBalances; base::flat_map<PeerId, CreditsAmount> _cachedPeerCurrencyBalances;
CreditsAmount _balance; CreditsAmount _balance;
CreditsAmount _locked; CreditsAmount _locked;

View file

@ -1468,14 +1468,14 @@ void ApplyChannelUpdate(
const auto currencyLoadLifetime = std::make_shared<rpl::lifetime>(); const auto currencyLoadLifetime = std::make_shared<rpl::lifetime>();
const auto currencyLoad const auto currencyLoad
= currencyLoadLifetime->make_state<Api::EarnStatistics>(channel); = currencyLoadLifetime->make_state<Api::EarnStatistics>(channel);
const auto apply = [=](Data::EarnInt balance) { const auto apply = [=](const CreditsAmount &balance) {
if (const auto strong = weak.get()) { if (const auto strong = weak.get()) {
strong->credits().applyCurrency(id, balance); strong->credits().applyCurrency(id, balance);
} }
currencyLoadLifetime->destroy(); currencyLoadLifetime->destroy();
}; };
currencyLoad->request() | rpl::start_with_error_done( currencyLoad->request() | rpl::start_with_error_done(
[=](const QString &error) { apply(0); }, [=](const QString &error) { apply({}); },
[=] { apply(currencyLoad->data().currentBalance); }, [=] { apply(currencyLoad->data().currentBalance); },
*currencyLoadLifetime); *currencyLoadLifetime);
base::timer_once(kTimeout) | rpl::start_with_next([=] { base::timer_once(kTimeout) | rpl::start_with_next([=] {

View file

@ -33,7 +33,7 @@ struct EarnHistoryEntry final {
Type type; Type type;
Status status; Status status;
EarnInt amount = 0; CreditsAmount amount;
QDateTime date; QDateTime date;
QDateTime dateTo; QDateTime dateTo;
@ -45,7 +45,7 @@ struct EarnHistoryEntry final {
}; };
struct EarnHistorySlice final { struct EarnHistorySlice final {
using OffsetToken = int; using OffsetToken = QString;
std::vector<EarnHistoryEntry> list; std::vector<EarnHistoryEntry> list;
int total = 0; int total = 0;
bool allLoaded = false; bool allLoaded = false;
@ -58,9 +58,9 @@ struct EarnStatistics final {
} }
Data::StatisticalGraph topHoursGraph; Data::StatisticalGraph topHoursGraph;
Data::StatisticalGraph revenueGraph; Data::StatisticalGraph revenueGraph;
EarnInt currentBalance = 0; CreditsAmount currentBalance;
EarnInt availableBalance = 0; CreditsAmount availableBalance;
EarnInt overallRevenue = 0; CreditsAmount overallRevenue;
float64 usdRate = 0.; float64 usdRate = 0.;
bool switchedOff = false; bool switchedOff = false;

View file

@ -790,14 +790,14 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
= std::make_shared<rpl::lifetime>(); = std::make_shared<rpl::lifetime>();
const auto currencyLoad const auto currencyLoad
= currencyLoadLifetime->make_state<Api::EarnStatistics>(user); = currencyLoadLifetime->make_state<Api::EarnStatistics>(user);
const auto apply = [=](Data::EarnInt balance) { const auto apply = [=](const CreditsAmount &balance) {
if (const auto strong = weak.get()) { if (const auto strong = weak.get()) {
strong->credits().applyCurrency(id, balance); strong->credits().applyCurrency(id, balance);
} }
currencyLoadLifetime->destroy(); currencyLoadLifetime->destroy();
}; };
currencyLoad->request() | rpl::start_with_error_done( currencyLoad->request() | rpl::start_with_error_done(
[=](const QString &error) { apply(0); }, [=](const QString &error) { apply({}); },
[=] { apply(currencyLoad->data().currentBalance); }, [=] { apply(currencyLoad->data().currentBalance); },
*currencyLoadLifetime); *currencyLoadLifetime);
base::timer_once(kTimeout) | rpl::start_with_next([=] { base::timer_once(kTimeout) | rpl::start_with_next([=] {

View file

@ -22,6 +22,10 @@ QString MajorPart(EarnInt value) {
return (diff <= 0) ? QString(kZero) : string.mid(0, diff); return (diff <= 0) ? QString(kZero) : string.mid(0, diff);
} }
QString MajorPart(CreditsAmount value) {
return QString::number(int64(value.value()));
}
QString MinorPart(EarnInt value) { QString MinorPart(EarnInt value) {
if (!value) { if (!value) {
return QString(kDot) + kZero + kZero; return QString(kDot) + kZero + kZero;
@ -46,6 +50,10 @@ QString MinorPart(EarnInt value) {
return result.chopped(zeroCount); return result.chopped(zeroCount);
} }
QString MinorPart(CreditsAmount value) {
return QString::number(value.value(), 'f', 2).right(3);
}
QString ToUsd( QString ToUsd(
Data::EarnInt value, Data::EarnInt value,
float64 rate, float64 rate,

View file

@ -12,7 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Info::ChannelEarn { namespace Info::ChannelEarn {
[[nodiscard]] QString MajorPart(Data::EarnInt value); [[nodiscard]] QString MajorPart(Data::EarnInt value);
[[nodiscard]] QString MajorPart(CreditsAmount value);
[[nodiscard]] QString MinorPart(Data::EarnInt value); [[nodiscard]] QString MinorPart(Data::EarnInt value);
[[nodiscard]] QString MinorPart(CreditsAmount value);
[[nodiscard]] QString ToUsd( [[nodiscard]] QString ToUsd(
Data::EarnInt value, Data::EarnInt value,
float64 rate, float64 rate,

View file

@ -249,7 +249,6 @@ void InnerWidget::load() {
) | rpl::start_with_next([=, peerId = _peer->id]( ) | rpl::start_with_next([=, peerId = _peer->id](
const MTPUpdates &updates) { const MTPUpdates &updates) {
using TLCreditsUpdate = MTPDupdateStarsRevenueStatus; using TLCreditsUpdate = MTPDupdateStarsRevenueStatus;
using TLCurrencyUpdate = MTPDupdateBroadcastRevenueTransactions;
using TLNotificationUpdate = MTPDupdateServiceNotification; using TLNotificationUpdate = MTPDupdateServiceNotification;
Api::PerformForUpdate<TLCreditsUpdate>(updates, [&]( Api::PerformForUpdate<TLCreditsUpdate>(updates, [&](
const TLCreditsUpdate &d) { const TLCreditsUpdate &d) {
@ -257,29 +256,39 @@ void InnerWidget::load() {
return; return;
} }
const auto &data = d.vstatus().data(); const auto &data = d.vstatus().data();
auto &e = _state.creditsEarn; const auto isCredits = data.vcurrent_balance().match([](
e.currentBalance = CreditsAmountFromTL(data.vcurrent_balance()); const MTPDstarsAmount &) {
e.availableBalance = CreditsAmountFromTL(data.vavailable_balance()); return true;
e.overallRevenue = CreditsAmountFromTL(data.voverall_revenue()); }, [](const MTPDstarsTonAmount &) {
e.isWithdrawalEnabled = data.is_withdrawal_enabled(); return false;
e.nextWithdrawalAt = data.vnext_withdrawal_at()
? base::unixtime::parse(
data.vnext_withdrawal_at()->v)
: QDateTime();
state->apiCreditsHistory.request({}, [=](
const Data::CreditsStatusSlice &data) {
_state.creditsStatusSlice = data;
_stateUpdated.fire({});
}); });
}); if (isCredits) {
Api::PerformForUpdate<TLCurrencyUpdate>(updates, [&]( auto &credits = _state.creditsEarn;
const TLCurrencyUpdate &d) { credits.currentBalance = CreditsAmountFromTL(
if (peerId == peerFromMTP(d.vpeer())) { data.vcurrent_balance());
const auto &data = d.vbalances().data(); credits.availableBalance = CreditsAmountFromTL(
auto &e = _state.currencyEarn; data.vavailable_balance());
e.currentBalance = data.vcurrent_balance().v; credits.overallRevenue = CreditsAmountFromTL(
e.availableBalance = data.vavailable_balance().v; data.voverall_revenue());
e.overallRevenue = data.voverall_revenue().v; credits.isWithdrawalEnabled
= data.is_withdrawal_enabled();
credits.nextWithdrawalAt = data.vnext_withdrawal_at()
? base::unixtime::parse(
data.vnext_withdrawal_at()->v)
: QDateTime();
state->apiCreditsHistory.request({}, [=](
const Data::CreditsStatusSlice &data) {
_state.creditsStatusSlice = data;
_stateUpdated.fire({});
});
} else {
auto &currency = _state.currencyEarn;
currency.currentBalance = CreditsAmountFromTL(
data.vcurrent_balance());
currency.availableBalance = CreditsAmountFromTL(
data.vavailable_balance());
currency.overallRevenue = CreditsAmountFromTL(
data.voverall_revenue());
_stateUpdated.fire({}); _stateUpdated.fire({});
} }
}); });
@ -405,7 +414,7 @@ void InnerWidget::fill() {
const auto withdrawalEnabled = WithdrawalEnabled(session); const auto withdrawalEnabled = WithdrawalEnabled(session);
const auto addEmojiToMajor = [=]( const auto addEmojiToMajor = [=](
not_null<Ui::FlatLabel*> label, not_null<Ui::FlatLabel*> label,
rpl::producer<EarnInt> value, rpl::producer<CreditsAmount> value,
std::optional<bool> isIn, std::optional<bool> isIn,
std::optional<QMargins> margins) { std::optional<QMargins> margins) {
const auto &st = label->st(); const auto &st = label->st();
@ -425,9 +434,11 @@ void InnerWidget::fill() {
: TextWithEntities::Simple((*isIn) ? QChar('+') : kMinus); : TextWithEntities::Simple((*isIn) ? QChar('+') : kMinus);
std::move( std::move(
value value
) | rpl::start_with_next([=](EarnInt v) { ) | rpl::start_with_next([=](CreditsAmount v) {
label->setMarkedText( label->setMarkedText(
base::duplicate(prepended).append(icon).append(MajorPart(v)), base::duplicate(prepended)
.append(icon)
.append(QString::number(v.whole())),
Core::TextContext({ .session = session })); Core::TextContext({ .session = session }));
}, label->lifetime()); }, label->lifetime());
}; };
@ -706,7 +717,7 @@ void InnerWidget::fill() {
Ui::AddSkip(container, st::channelEarnOverviewTitleSkip); Ui::AddSkip(container, st::channelEarnOverviewTitleSkip);
const auto addOverview = [&]( const auto addOverview = [&](
rpl::producer<EarnInt> currencyValue, rpl::producer<CreditsAmount> currencyValue,
rpl::producer<CreditsAmount> creditsValue, rpl::producer<CreditsAmount> creditsValue,
const tr::phrase<> &text, const tr::phrase<> &text,
bool showCurrency, bool showCurrency,
@ -724,15 +735,17 @@ void InnerWidget::fill() {
{}); {});
const auto minorLabel = Ui::CreateChild<Ui::FlatLabel>( const auto minorLabel = Ui::CreateChild<Ui::FlatLabel>(
line, line,
rpl::duplicate(currencyValue) | rpl::map([=](EarnInt v) { rpl::duplicate(
return MinorPart(v).left(kMinorLength); currencyValue
) | rpl::map([](CreditsAmount v) {
return MinorPart(v);
}), }),
st::channelEarnOverviewMinorLabel); st::channelEarnOverviewMinorLabel);
const auto secondMinorLabel = Ui::CreateChild<Ui::FlatLabel>( const auto secondMinorLabel = Ui::CreateChild<Ui::FlatLabel>(
line, line,
std::move( std::move(
currencyValue currencyValue
) | rpl::map([=](EarnInt value) { ) | rpl::map([=](CreditsAmount value) {
return value return value
? ToUsd(value, multiplier, kMinorLength) ? ToUsd(value, multiplier, kMinorLength)
: QString(); : QString();

View file

@ -849,19 +849,20 @@ template <typename Text, typename ToggleOn, typename Callback>
st)); st));
} }
rpl::producer<uint64> AddCurrencyAction( rpl::producer<CreditsAmount> AddCurrencyAction(
not_null<UserData*> user, not_null<UserData*> user,
not_null<Ui::VerticalLayout*> wrap, not_null<Ui::VerticalLayout*> wrap,
not_null<Controller*> controller) { not_null<Controller*> controller) {
struct State final { struct State final {
rpl::variable<uint64> balance; rpl::variable<CreditsAmount> balance;
}; };
const auto state = wrap->lifetime().make_state<State>(); const auto state = wrap->lifetime().make_state<State>();
const auto parentController = controller->parentController(); const auto parentController = controller->parentController();
const auto wrapButton = AddActionButton( const auto wrapButton = AddActionButton(
wrap, wrap,
tr::lng_manage_peer_bot_balance_currency(), tr::lng_manage_peer_bot_balance_currency(),
state->balance.value() | rpl::map(rpl::mappers::_1 > 0), state->balance.value(
) | rpl::map(rpl::mappers::_1 > CreditsAmount(0)),
[=] { parentController->showSection(Info::ChannelEarn::Make(user)); }, [=] { parentController->showSection(Info::ChannelEarn::Make(user)); },
nullptr); nullptr);
{ {
@ -889,14 +890,14 @@ rpl::producer<uint64> AddCurrencyAction(
= std::make_shared<rpl::lifetime>(); = std::make_shared<rpl::lifetime>();
const auto currencyLoad const auto currencyLoad
= currencyLoadLifetime->make_state<Api::EarnStatistics>(user); = currencyLoadLifetime->make_state<Api::EarnStatistics>(user);
const auto done = [=](Data::EarnInt balance) { const auto done = [=](CreditsAmount balance) {
if ([[maybe_unused]] const auto strong = weak.data()) { if ([[maybe_unused]] const auto strong = weak.data()) {
state->balance = balance; state->balance = balance;
currencyLoadLifetime->destroy(); currencyLoadLifetime->destroy();
} }
}; };
currencyLoad->request() | rpl::start_with_error_done( currencyLoad->request() | rpl::start_with_error_done(
[=](const QString &error) { done(0); }, [=](const QString &error) { done({}); },
[=] { done(currencyLoad->data().currentBalance); }, [=] { done(currencyLoad->data().currentBalance); },
*currencyLoadLifetime); *currencyLoadLifetime);
} }
@ -918,7 +919,7 @@ rpl::producer<uint64> AddCurrencyAction(
) | rpl::start_with_next([=, &st]( ) | rpl::start_with_next([=, &st](
int width, int width,
const QString &button, const QString &button,
Data::EarnInt balance) { CreditsAmount balance) {
const auto available = width const auto available = width
- rect::m::sum::h(st.padding) - rect::m::sum::h(st.padding)
- st.style.font->width(button) - st.style.font->width(button)
@ -2404,7 +2405,7 @@ void ActionsFiller::addBalanceActions(not_null<UserData*> user) {
rpl::combine( rpl::combine(
std::move(currencyBalance), std::move(currencyBalance),
std::move(creditsBalance) std::move(creditsBalance)
) | rpl::map((rpl::mappers::_1 > 0) ) | rpl::map((rpl::mappers::_1 > CreditsAmount(0))
|| (rpl::mappers::_2 > CreditsAmount(0)))); || (rpl::mappers::_2 > CreditsAmount(0))));
} }
@ -2915,18 +2916,20 @@ object_ptr<Ui::RpWidget> SetupChannelMembersAndManage(
auto creditsValue = rpl::single( auto creditsValue = rpl::single(
rpl::empty_value() rpl::empty_value()
) | rpl::then(rpl::duplicate(refreshed)) | rpl::map([=] { ) | rpl::then(rpl::duplicate(refreshed)) | rpl::map([=] {
return channel->session().credits().balance(channel->id).whole(); return channel->session().credits().balance(channel->id);
}); });
auto currencyValue = rpl::single( auto currencyValue = rpl::single(
rpl::empty_value() rpl::empty_value()
) | rpl::then(rpl::duplicate(refreshed)) | rpl::map([=] { ) | rpl::then(rpl::duplicate(refreshed)) | rpl::map([=] {
return channel->session().credits().balanceCurrency(channel->id); return channel->session().credits().balanceCurrency(channel->id);
}); });
const auto emptyAmount = CreditsAmount(0);
balanceWrap->toggleOn( balanceWrap->toggleOn(
rpl::combine( rpl::combine(
rpl::duplicate(creditsValue), rpl::duplicate(creditsValue),
rpl::duplicate(currencyValue) rpl::duplicate(currencyValue)
) | rpl::map(rpl::mappers::_1 > 0 || rpl::mappers::_2 > 0), ) | rpl::map(rpl::mappers::_1 > emptyAmount
|| rpl::mappers::_2 > emptyAmount),
anim::type::normal); anim::type::normal);
balanceWrap->finishAnimating(); balanceWrap->finishAnimating();
@ -2961,13 +2964,14 @@ object_ptr<Ui::RpWidget> SetupChannelMembersAndManage(
rpl::combine( rpl::combine(
std::move(creditsValue), std::move(creditsValue),
std::move(currencyValue) std::move(currencyValue)
) | rpl::map([](uint64 credits, uint64 currency) { ) | rpl::map([](CreditsAmount credits, CreditsAmount currency) {
auto creditsText = (credits > 0) auto creditsText = (credits > CreditsAmount(0))
? Ui::Text::SingleCustomEmoji(Ui::kCreditsCurrency) ? Ui::Text::SingleCustomEmoji(Ui::kCreditsCurrency)
.append(QChar(' ')) .append(QChar(' '))
.append(QString::number(credits)) .append(Info::ChannelEarn::MajorPart(credits))
.append(Info::ChannelEarn::MinorPart(credits))
: TextWithEntities(); : TextWithEntities();
auto currencyText = (currency > 0) auto currencyText = (currency > CreditsAmount(0))
? Ui::Text::SingleCustomEmoji("_") ? Ui::Text::SingleCustomEmoji("_")
.append(QChar(' ')) .append(QChar(' '))
.append(Info::ChannelEarn::MajorPart(currency)) .append(Info::ChannelEarn::MajorPart(currency))

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_statistics.h" #include "api/api_statistics.h"
#include "boxes/peer_list_controllers.h" #include "boxes/peer_list_controllers.h"
#include "boxes/peer_list_widgets.h" #include "boxes/peer_list_widgets.h"
#include "info/channel_statistics/earn/earn_format.h"
#include "chat_helpers/stickers_gift_box_pack.h" #include "chat_helpers/stickers_gift_box_pack.h"
#include "core/ui_integration.h" // TextContext #include "core/ui_integration.h" // TextContext
#include "data/data_channel.h" #include "data/data_channel.h"