Update API scheme on layer 206.

This commit is contained in:
John Preston 2025-06-23 18:10:07 +04:00
parent dc19f2e76c
commit 0fa50f1951
57 changed files with 556 additions and 348 deletions

View file

@ -470,6 +470,7 @@ PRIVATE
core/crash_report_window.h
core/crash_reports.cpp
core/crash_reports.h
core/credits_amount.h
core/deadlock_detector.h
core/file_utilities.cpp
core/file_utilities.h
@ -483,7 +484,6 @@ PRIVATE
core/sandbox.h
core/shortcuts.cpp
core/shortcuts.h
core/stars_amount.h
core/ui_integration.cpp
core/ui_integration.h
core/update_checker.cpp

View file

@ -19,7 +19,7 @@ MTPSuggestedPost SuggestToMTP(SuggestPostOptions suggest) {
return suggest.exists
? MTP_suggestedPost(
MTP_flags(suggest.date ? Flag::f_schedule_date : Flag()),
MTP_long(suggest.stars),
StarsAmountToTL(suggest.price()),
MTP_int(suggest.date))
: MTPSuggestedPost();
}

View file

@ -80,16 +80,15 @@ constexpr auto kTransactionsLimit = 100;
}, [](const auto &) { return (const MTPDstarGift*)nullptr; })
: nullptr;
const auto reaction = tl.data().is_reaction();
const auto amount = Data::FromTL(tl.data().vstars());
const auto starrefAmount = tl.data().vstarref_amount()
? Data::FromTL(*tl.data().vstarref_amount())
: StarsAmount();
const auto amount = CreditsAmountFromTL(tl.data().vstars());
const auto starrefAmount = CreditsAmountFromTL(
tl.data().vstarref_amount());
const auto starrefCommission
= tl.data().vstarref_commission_permille().value_or_empty();
const auto starrefBarePeerId = tl.data().vstarref_peer()
? peerFromMTP(*tl.data().vstarref_peer()).value
: 0;
const auto incoming = (amount >= StarsAmount());
const auto incoming = (amount >= CreditsAmount());
const auto paidMessagesCount
= tl.data().vpaid_messages().value_or_empty();
const auto premiumMonthsForStars
@ -108,7 +107,7 @@ constexpr auto kTransactionsLimit = 100;
.date = base::unixtime::parse(tl.data().vdate().v),
.photoId = photo ? photo->id : 0,
.extended = std::move(extended),
.credits = Data::FromTL(tl.data().vstars()),
.credits = CreditsAmountFromTL(tl.data().vstars()),
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
.barePeerId = saveActorId ? peer->id.value : barePeerId,
.bareGiveawayMsgId = uint64(
@ -116,7 +115,7 @@ constexpr auto kTransactionsLimit = 100;
.bareGiftStickerId = giftStickerId,
.bareActorId = saveActorId ? barePeerId : uint64(0),
.uniqueGift = parsedGift ? parsedGift->unique : nullptr,
.starrefAmount = paidMessagesCount ? StarsAmount() : starrefAmount,
.starrefAmount = paidMessagesCount ? CreditsAmount() : starrefAmount,
.starrefCommission = paidMessagesCount ? 0 : starrefCommission,
.starrefRecipientId = paidMessagesCount ? 0 : starrefBarePeerId,
.peerType = tl.data().vpeer().match([](const HistoryPeerTL &) {
@ -147,7 +146,7 @@ constexpr auto kTransactionsLimit = 100;
.paidMessagesCount = paidMessagesCount,
.paidMessagesAmount = (paidMessagesCount
? starrefAmount
: StarsAmount()),
: CreditsAmount()),
.paidMessagesCommission = paidMessagesCount ? starrefCommission : 0,
.starsConverted = int(nonUniqueGift
? nonUniqueGift->vconvert_stars().v
@ -216,7 +215,7 @@ constexpr auto kTransactionsLimit = 100;
return Data::CreditsStatusSlice{
.list = std::move(entries),
.subscriptions = std::move(subscriptions),
.balance = Data::FromTL(status.data().vbalance()),
.balance = CreditsAmountFromTL(status.data().vbalance()),
.subscriptionsMissingBalance
= status.data().vsubscriptions_missing_balance().value_or_empty(),
.allLoaded = !status.data().vnext_offset().has_value()
@ -300,11 +299,14 @@ void CreditsStatus::request(
using TLResult = MTPpayments_StarsStatus;
_requestId = _api.request(MTPpayments_GetStarsStatus(
MTP_flags(0),
_peer->isSelf() ? MTP_inputPeerSelf() : _peer->input
)).done([=](const TLResult &result) {
_requestId = 0;
const auto &balance = result.data().vbalance();
_peer->session().credits().apply(_peer->id, Data::FromTL(balance));
_peer->session().credits().apply(
_peer->id,
CreditsAmountFromTL(balance));
if (const auto onstack = done) {
onstack(StatusFromTL(result, _peer));
}
@ -420,13 +422,15 @@ rpl::producer<rpl::no_value, QString> CreditsEarnStatistics::request() {
)).done([=](const MTPpayments_StarsRevenueStats &result) {
const auto &data = result.data();
const auto &status = data.vstatus().data();
using Data::FromTL;
_data = Data::CreditsEarnStatistics{
.revenueGraph = StatisticalGraphFromTL(
data.vrevenue_graph()),
.currentBalance = FromTL(status.vcurrent_balance()),
.availableBalance = FromTL(status.vavailable_balance()),
.overallRevenue = FromTL(status.voverall_revenue()),
.currentBalance = CreditsAmountFromTL(
status.vcurrent_balance()),
.availableBalance = CreditsAmountFromTL(
status.vavailable_balance()),
.overallRevenue = CreditsAmountFromTL(
status.voverall_revenue()),
.usdRate = data.vusd_rate().v,
.isWithdrawalEnabled = status.is_withdrawal_enabled(),
.nextWithdrawalAt = status.vnext_withdrawal_at()

View file

@ -220,7 +220,9 @@ void SendSuggest(
auto action = SendAction(item->history());
action.options.suggest.exists = 1;
action.options.suggest.date = suggestion->date;
action.options.suggest.stars = suggestion->stars;
action.options.suggest.priceWhole = suggestion->price.whole();
action.options.suggest.priceNano = suggestion->price.nano();
action.options.suggest.ton = suggestion->price.ton() ? 1 : 0;
action.options.starsApproved = starsApproved;
action.replyTo.monoforumPeerId = item->history()->amMonoforumAdmin()
? item->sublistPeerId()
@ -308,8 +310,10 @@ void SuggestApprovalPrice(
.session = &controller->session(),
.done = done,
.value = {
.exists = true,
.stars = uint32(suggestion->stars),
.exists = uint32(1),
.priceWhole = uint32(suggestion->price.whole()),
.priceNano = uint32(suggestion->price.nano()),
.ton = uint32(suggestion->price.ton() ? 1 : 0),
.date = suggestion->date,
},
.mode = SuggestMode::Change,
@ -403,8 +407,10 @@ std::shared_ptr<ClickHandler> SuggestChangesClickHandler(
.monoforumPeerId = monoforumPeerId,
},
SuggestPostOptions{
.exists = 1,
.stars = uint32(suggestion->stars),
.exists = uint32(1),
.priceWhole = uint32(suggestion->price.whole()),
.priceNano = uint32(suggestion->price.nano()),
.ton = uint32(suggestion->price.ton() ? 1 : 0),
.date = suggestion->date,
},
cursor,

View file

@ -2756,6 +2756,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->credits().apply(data);
} break;
case mtpc_updateStarsTonBalance: {
const auto &data = update.c_updateStarsBalance();
_session->credits().apply(data);
} break;
case mtpc_updatePaidReactionPrivacy: {
const auto &data = update.c_updatePaidReactionPrivacy();
_session->api().globalPrivacy().updatePaidReactionShownPeer(

View file

@ -99,7 +99,7 @@ void GiftCreditsBox(
Main::MakeSessionShow(box->uiShow(), &peer->session()),
box->verticalLayout(),
peer,
StarsAmount(),
CreditsAmount(),
[=] { gifted(); box->uiShow()->hideLayer(); },
tr::lng_credits_summary_options_subtitle(),
{});

View file

@ -411,7 +411,7 @@ void AddTableRow(
table->st().defaultValue.style.font->height);
const auto label = Ui::CreateChild<Ui::FlatLabel>(
raw,
Lang::FormatStarsAmountDecimal(entry.credits),
Lang::FormatCreditsAmountDecimal(entry.credits),
table->st().defaultValue,
st::defaultPopupMenu);
@ -1630,8 +1630,8 @@ void AddCreditsHistoryEntryTable(
const auto full = int(base::SafeRound(entry.credits.value()
/ (1. - (entry.starrefCommission / 1000.))));
auto value = Ui::Text::IconEmoji(&st::starIconEmojiColored);
const auto starsText = Lang::FormatStarsAmountDecimal(
StarsAmount{ full });
const auto starsText = Lang::FormatCreditsAmountDecimal(
CreditsAmount{ full });
AddTableRow(
table,
tr::lng_credits_box_history_entry_gift_full_price(),
@ -1787,7 +1787,7 @@ void AddCreditsHistoryEntryTable(
auto value = Ui::Text::IconEmoji(&st::starIconEmojiColored);
const auto full = (entry.in ? 1 : -1)
* (entry.credits + entry.paidMessagesAmount);
const auto starsText = Lang::FormatStarsAmountDecimal(full);
const auto starsText = Lang::FormatCreditsAmountDecimal(full);
AddTableRow(
table,
tr::lng_credits_paid_messages_full(),

View file

@ -1095,8 +1095,8 @@ void Controller::fillDirectMessagesButton() {
: rpl::single(Ui::Text::IconEmoji(
&st::starIconEmojiColored
).append(' ').append(
Lang::FormatStarsAmountDecimal(
StarsAmount{ starsPerMessage })));
Lang::FormatCreditsAmountDecimal(
CreditsAmount{ starsPerMessage })));
}) | rpl::flatten_latest();
AddButtonWithText(
_controls.buttonsLayout,
@ -1907,7 +1907,7 @@ void Controller::fillBotCreditsButton() {
auto &lifetime = _controls.buttonsLayout->lifetime();
const auto state = lifetime.make_state<State>();
if (const auto balance = _peer->session().credits().balance(_peer->id)) {
state->balance = Lang::FormatStarsAmountDecimal(balance);
state->balance = Lang::FormatCreditsAmountDecimal(balance);
}
const auto wrap = _controls.buttonsLayout->add(
@ -1932,7 +1932,7 @@ void Controller::fillBotCreditsButton() {
if (data.balance) {
wrap->toggle(true, anim::type::normal);
}
state->balance = Lang::FormatStarsAmountDecimal(data.balance);
state->balance = Lang::FormatCreditsAmountDecimal(data.balance);
});
}
{

View file

@ -2007,7 +2007,7 @@ void SoldOutBox(
Data::CreditsHistoryEntry{
.firstSaleDate = base::unixtime::parse(gift.info.firstSaleDate),
.lastSaleDate = base::unixtime::parse(gift.info.lastSaleDate),
.credits = StarsAmount(gift.info.stars),
.credits = CreditsAmount(gift.info.stars),
.bareGiftStickerId = gift.info.document->id,
.peerType = Data::CreditsHistoryEntry::PeerType::Peer,
.limitedCount = gift.info.limitedCount,
@ -2039,8 +2039,8 @@ void AddUpgradeButton(
tr::lng_gift_send_unique(
lt_price,
rpl::single(star.append(' '
+ Lang::FormatStarsAmountDecimal(
StarsAmount{ cost }))),
+ Lang::FormatCreditsAmountDecimal(
CreditsAmount{ cost }))),
Text::WithEntities),
st::boxLabel,
st::defaultPopupMenu,
@ -2355,9 +2355,9 @@ void SendGiftBox(
tr::lng_gift_send_stars_balance(
lt_amount,
peer->session().credits().balanceValue(
) | rpl::map([=](StarsAmount amount) {
) | rpl::map([=](CreditsAmount amount) {
return base::duplicate(star).append(
Lang::FormatStarsAmountDecimal(amount));
Lang::FormatCreditsAmountDecimal(amount));
}),
lt_link,
tr::lng_gift_send_stars_balance_link(
@ -4614,8 +4614,8 @@ void UpgradeBox(
? tr::lng_gift_upgrade_button(
lt_price,
rpl::single(star.append(
' ' + Lang::FormatStarsAmountDecimal(
StarsAmount{ cost }))),
' ' + Lang::FormatCreditsAmountDecimal(
CreditsAmount{ cost }))),
Ui::Text::WithEntities)
: tr::lng_gift_upgrade_confirm(Ui::Text::WithEntities)),
&controller->session(),

View file

@ -0,0 +1,155 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/basic_types.h"
class MTPstarsAmount;
namespace tl {
template <typename bare>
class boxed;
} // namespace tl
using MTPStarsAmount = tl::boxed<MTPstarsAmount>;
inline constexpr auto kOneStarInNano = int64(1'000'000'000);
enum class CreditsType {
Stars,
Ton,
};
class CreditsAmount {
public:
CreditsAmount() = default;
explicit CreditsAmount(
int64 whole,
CreditsType type = CreditsType::Stars)
: _ton((type == CreditsType::Ton) ? 1 : 0)
, _whole(whole) {
}
CreditsAmount(
int64 whole,
int64 nano,
CreditsType type = CreditsType::Stars)
: _ton((type == CreditsType::Ton) ? 1 : 0)
, _whole(whole)
, _nano(nano) {
normalize();
}
[[nodiscard]] int64 whole() const {
return _whole;
}
[[nodiscard]] int64 nano() const {
return _nano;
}
[[nodiscard]] double value() const {
return double(_whole) + double(_nano) / kOneStarInNano;
}
[[nodiscard]] bool ton() const {
return (_ton == 1);
}
[[nodiscard]] bool stars() const {
return (_ton == 0);
}
[[nodiscard]] CreditsType type() const {
return !_ton ? CreditsType::Stars : CreditsType::Ton;
}
[[nodiscard]] bool empty() const {
return !_whole && !_nano;
}
[[nodiscard]] inline bool operator!() const {
return empty();
}
[[nodiscard]] inline explicit operator bool() const {
return !empty();
}
inline CreditsAmount &operator+=(CreditsAmount other) {
_whole += other._whole;
_nano += other._nano;
normalize();
return *this;
}
inline CreditsAmount &operator-=(CreditsAmount other) {
_whole -= other._whole;
_nano -= other._nano;
normalize();
return *this;
}
inline CreditsAmount &operator*=(int64 multiplier) {
_whole *= multiplier;
_nano *= multiplier;
normalize();
return *this;
}
inline CreditsAmount operator-() const {
auto result = *this;
result *= -1;
return result;
}
friend inline auto operator<=>(CreditsAmount, CreditsAmount) = default;
friend inline bool operator==(CreditsAmount, CreditsAmount) = default;
[[nodiscard]] CreditsAmount abs() const {
return (_whole < 0) ? CreditsAmount(-_whole, -_nano) : *this;
}
private:
void normalize() {
if (_nano < 0) {
const auto shifts = (-_nano + kOneStarInNano - 1)
/ kOneStarInNano;
_nano += shifts * kOneStarInNano;
_whole -= shifts;
} else if (_nano >= kOneStarInNano) {
const auto shifts = _nano / kOneStarInNano;
_nano -= shifts * kOneStarInNano;
_whole += shifts;
}
}
int64 _ton : 2 = 0;
int64 _whole : 62 = 0;
int64 _nano = 0;
};
[[nodiscard]] inline CreditsAmount operator+(
CreditsAmount a,
CreditsAmount b) {
return a += b;
}
[[nodiscard]] inline CreditsAmount operator-(
CreditsAmount a,
CreditsAmount b) {
return a -= b;
}
[[nodiscard]] inline CreditsAmount operator*(CreditsAmount a, int64 b) {
return a *= b;
}
[[nodiscard]] inline CreditsAmount operator*(int64 a, CreditsAmount b) {
return b *= a;
}
[[nodiscard]] CreditsAmount CreditsAmountFromTL(
const MTPStarsAmount &amount);
[[nodiscard]] CreditsAmount CreditsAmountFromTL(
const MTPStarsAmount *amount);
[[nodiscard]] MTPStarsAmount StarsAmountToTL(CreditsAmount amount);

View file

@ -1,108 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/basic_types.h"
inline constexpr auto kOneStarInNano = int64(1'000'000'000);
class StarsAmount {
public:
StarsAmount() = default;
explicit StarsAmount(int64 whole) : _whole(whole) {}
StarsAmount(int64 whole, int64 nano) : _whole(whole), _nano(nano) {
normalize();
}
[[nodiscard]] int64 whole() const {
return _whole;
}
[[nodiscard]] int64 nano() const {
return _nano;
}
[[nodiscard]] double value() const {
return double(_whole) + double(_nano) / kOneStarInNano;
}
[[nodiscard]] bool empty() const {
return !_whole && !_nano;
}
[[nodiscard]] inline bool operator!() const {
return empty();
}
[[nodiscard]] inline explicit operator bool() const {
return !empty();
}
inline StarsAmount &operator+=(StarsAmount other) {
_whole += other._whole;
_nano += other._nano;
normalize();
return *this;
}
inline StarsAmount &operator-=(StarsAmount other) {
_whole -= other._whole;
_nano -= other._nano;
normalize();
return *this;
}
inline StarsAmount &operator*=(int64 multiplier) {
_whole *= multiplier;
_nano *= multiplier;
normalize();
return *this;
}
inline StarsAmount operator-() const {
auto result = *this;
result *= -1;
return result;
}
friend inline auto operator<=>(StarsAmount, StarsAmount) = default;
friend inline bool operator==(StarsAmount, StarsAmount) = default;
[[nodiscard]] StarsAmount abs() const {
return (_whole < 0) ? StarsAmount(-_whole, -_nano) : *this;
}
private:
int64 _whole = 0;
int64 _nano = 0;
void normalize() {
if (_nano < 0) {
const auto shifts = (-_nano + kOneStarInNano - 1)
/ kOneStarInNano;
_nano += shifts * kOneStarInNano;
_whole -= shifts;
} else if (_nano >= kOneStarInNano) {
const auto shifts = _nano / kOneStarInNano;
_nano -= shifts * kOneStarInNano;
_whole += shifts;
}
}
};
[[nodiscard]] inline StarsAmount operator+(StarsAmount a, StarsAmount b) {
return a += b;
}
[[nodiscard]] inline StarsAmount operator-(StarsAmount a, StarsAmount b) {
return a -= b;
}
[[nodiscard]] inline StarsAmount operator*(StarsAmount a, int64 b) {
return a *= b;
}
[[nodiscard]] inline StarsAmount operator*(int64 a, StarsAmount b) {
return b *= a;
}

View file

@ -19,11 +19,6 @@ constexpr auto kReloadThreshold = 60 * crl::time(1000);
} // namespace
StarsAmount FromTL(const MTPStarsAmount &value) {
const auto &data = value.data();
return StarsAmount(data.vamount().v, data.vnanos().v);
}
Credits::Credits(not_null<Main::Session*> session)
: _session(session)
, _reload([=] { load(true); }) {
@ -32,7 +27,7 @@ Credits::Credits(not_null<Main::Session*> session)
Credits::~Credits() = default;
void Credits::apply(const MTPDupdateStarsBalance &data) {
apply(FromTL(data.vbalance()));
apply(CreditsAmountFromTL(data.vbalance()));
}
rpl::producer<float64> Credits::rateValue(
@ -80,13 +75,13 @@ rpl::producer<bool> Credits::loadedValue() const {
) | rpl::then(_loadedChanges.events() | rpl::map_to(true));
}
StarsAmount Credits::balance() const {
CreditsAmount Credits::balance() const {
return _nonLockedBalance.current();
}
StarsAmount Credits::balance(PeerId peerId) const {
CreditsAmount Credits::balance(PeerId peerId) const {
const auto it = _cachedPeerBalances.find(peerId);
return (it != _cachedPeerBalances.end()) ? it->second : StarsAmount();
return (it != _cachedPeerBalances.end()) ? it->second : CreditsAmount();
}
uint64 Credits::balanceCurrency(PeerId peerId) const {
@ -94,19 +89,19 @@ uint64 Credits::balanceCurrency(PeerId peerId) const {
return (it != _cachedPeerCurrencyBalances.end()) ? it->second : 0;
}
rpl::producer<StarsAmount> Credits::balanceValue() const {
rpl::producer<CreditsAmount> Credits::balanceValue() const {
return _nonLockedBalance.value();
}
void Credits::updateNonLockedValue() {
_nonLockedBalance = (_balance >= _locked)
? (_balance - _locked)
: StarsAmount();
: CreditsAmount();
}
void Credits::lock(StarsAmount count) {
void Credits::lock(CreditsAmount count) {
Expects(loaded());
Expects(count >= StarsAmount(0));
Expects(count >= CreditsAmount(0));
Expects(_locked + count <= _balance);
_locked += count;
@ -114,8 +109,8 @@ void Credits::lock(StarsAmount count) {
updateNonLockedValue();
}
void Credits::unlock(StarsAmount count) {
Expects(count >= StarsAmount(0));
void Credits::unlock(CreditsAmount count) {
Expects(count >= CreditsAmount(0));
Expects(_locked >= count);
_locked -= count;
@ -123,12 +118,12 @@ void Credits::unlock(StarsAmount count) {
updateNonLockedValue();
}
void Credits::withdrawLocked(StarsAmount count) {
Expects(count >= StarsAmount(0));
void Credits::withdrawLocked(CreditsAmount count) {
Expects(count >= CreditsAmount(0));
Expects(_locked >= count);
_locked -= count;
apply(_balance >= count ? (_balance - count) : StarsAmount(0));
apply(_balance >= count ? (_balance - count) : CreditsAmount(0));
invalidate();
}
@ -136,7 +131,7 @@ void Credits::invalidate() {
_reload.call();
}
void Credits::apply(StarsAmount balance) {
void Credits::apply(CreditsAmount balance) {
_balance = balance;
updateNonLockedValue();
@ -146,7 +141,7 @@ void Credits::apply(StarsAmount balance) {
}
}
void Credits::apply(PeerId peerId, StarsAmount balance) {
void Credits::apply(PeerId peerId, CreditsAmount balance) {
_cachedPeerBalances[peerId] = balance;
_refreshedByPeerId.fire_copy(peerId);
}
@ -166,3 +161,27 @@ bool Credits::statsEnabled() const {
}
} // namespace Data
CreditsAmount CreditsAmountFromTL(const MTPStarsAmount &amount) {
return amount.match([&](const MTPDstarsAmount &data) {
return CreditsAmount(
data.vamount().v,
data.vnanos().v,
CreditsType::Stars);
}, [&](const MTPDstarsTonAmount &data) {
return CreditsAmount(
data.vamount().v / uint64(1'000'000'000),
data.vamount().v % uint64(1'000'000'000),
CreditsType::Ton);
});
}
CreditsAmount CreditsAmountFromTL(const MTPStarsAmount *amount) {
return amount ? CreditsAmountFromTL(*amount) : CreditsAmount();
}
MTPStarsAmount StarsAmountToTL(CreditsAmount amount) {
return amount.ton() ? MTP_starsTonAmount(
MTP_long(amount.whole() * uint64(1'000'000'000) + amount.nano())
) : MTP_starsAmount(MTP_long(amount.whole()), MTP_int(amount.nano()));
}

View file

@ -13,23 +13,21 @@ class Session;
namespace Data {
[[nodiscard]] StarsAmount FromTL(const MTPStarsAmount &value);
class Credits final {
public:
explicit Credits(not_null<Main::Session*> session);
~Credits();
void load(bool force = false);
void apply(StarsAmount balance);
void apply(PeerId peerId, StarsAmount balance);
void apply(CreditsAmount balance);
void apply(PeerId peerId, CreditsAmount balance);
[[nodiscard]] bool loaded() const;
[[nodiscard]] rpl::producer<bool> loadedValue() const;
[[nodiscard]] StarsAmount balance() const;
[[nodiscard]] StarsAmount balance(PeerId peerId) const;
[[nodiscard]] rpl::producer<StarsAmount> balanceValue() const;
[[nodiscard]] CreditsAmount balance() const;
[[nodiscard]] CreditsAmount balance(PeerId peerId) const;
[[nodiscard]] rpl::producer<CreditsAmount> balanceValue() const;
[[nodiscard]] rpl::producer<float64> rateValue(
not_null<PeerData*> ownedBotOrChannel);
@ -40,9 +38,9 @@ public:
void applyCurrency(PeerId peerId, uint64 balance);
[[nodiscard]] uint64 balanceCurrency(PeerId peerId) const;
void lock(StarsAmount count);
void unlock(StarsAmount count);
void withdrawLocked(StarsAmount count);
void lock(CreditsAmount count);
void unlock(CreditsAmount count);
void withdrawLocked(CreditsAmount count);
void invalidate();
void apply(const MTPDupdateStarsBalance &data);
@ -54,12 +52,12 @@ private:
std::unique_ptr<rpl::lifetime> _loader;
base::flat_map<PeerId, StarsAmount> _cachedPeerBalances;
base::flat_map<PeerId, CreditsAmount> _cachedPeerBalances;
base::flat_map<PeerId, uint64> _cachedPeerCurrencyBalances;
StarsAmount _balance;
StarsAmount _locked;
rpl::variable<StarsAmount> _nonLockedBalance;
CreditsAmount _balance;
CreditsAmount _locked;
rpl::variable<CreditsAmount> _nonLockedBalance;
rpl::event_stream<> _loadedChanges;
crl::time _lastLoaded = 0;
float64 _rate = 0.;

View file

@ -59,7 +59,7 @@ struct CreditsHistoryEntry final {
QDateTime lastSaleDate;
PhotoId photoId = 0;
std::vector<CreditsHistoryMedia> extended;
StarsAmount credits;
CreditsAmount credits;
uint64 bareMsgId = 0;
uint64 barePeerId = 0;
uint64 bareGiveawayMsgId = 0;
@ -72,7 +72,7 @@ struct CreditsHistoryEntry final {
uint64 stargiftId = 0;
std::shared_ptr<UniqueGift> uniqueGift;
Fn<std::vector<CreditsHistoryEntry>()> pinnedSavedGifts;
StarsAmount starrefAmount;
CreditsAmount starrefAmount;
int starrefCommission = 0;
uint64 starrefRecipientId = 0;
PeerType peerType;
@ -80,7 +80,7 @@ struct CreditsHistoryEntry final {
QDateTime successDate;
QString successLink;
int paidMessagesCount = 0;
StarsAmount paidMessagesAmount;
CreditsAmount paidMessagesAmount;
int paidMessagesCommission = 0;
int limitedCount = 0;
int limitedLeft = 0;
@ -115,7 +115,7 @@ struct CreditsStatusSlice final {
using OffsetToken = QString;
std::vector<CreditsHistoryEntry> list;
std::vector<SubscriptionEntry> subscriptions;
StarsAmount balance;
CreditsAmount balance;
uint64 subscriptionsMissingBalance = 0;
bool allLoaded = false;
OffsetToken token;

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "core/stars_amount.h"
#include "core/credits_amount.h"
#include "data/data_statistics_chart.h"
#include <QtCore/QDateTime>
@ -22,9 +22,9 @@ struct CreditsEarnStatistics final {
&& overallRevenue;
}
Data::StatisticalGraph revenueGraph;
StarsAmount currentBalance;
StarsAmount availableBalance;
StarsAmount overallRevenue;
CreditsAmount currentBalance;
CreditsAmount availableBalance;
CreditsAmount overallRevenue;
float64 usdRate = 0.;
bool isWithdrawalEnabled = false;
QDateTime nextWithdrawalAt;

View file

@ -21,11 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
namespace Data {
namespace {
constexpr auto kMaxSuggestStars = 1'000'000'000;
} // namespace
WebPageDraft WebPageDraft::FromItem(not_null<HistoryItem*> item) {
const auto previewMedia = item->media();
@ -122,10 +117,10 @@ void ApplyPeerCloudDraft(
const auto &data = suggested->data();
suggest.exists = 1;
suggest.date = data.vschedule_date().value_or_empty();
suggest.stars = uint32(std::clamp(
data.vstars_amount().v,
uint64(),
uint64(kMaxSuggestStars)));
const auto price = CreditsAmountFromTL(data.vprice());
suggest.priceWhole = price.whole();
suggest.priceNano = price.nano();
suggest.ton = price.ton() ? 1 : 0;
}
auto cloudDraft = std::make_unique<Draft>(
textWithTags,

View file

@ -2514,7 +2514,7 @@ MediaGiftBox::MediaGiftBox(
not_null<HistoryItem*> parent,
not_null<PeerData*> from,
GiftType type,
int count)
int64 count)
: MediaGiftBox(parent, from, GiftCode{ .count = count, .type = type }) {
}

View file

@ -136,6 +136,7 @@ struct GiveawayResults {
enum class GiftType : uchar {
Premium, // count - months
Credits, // count - credits
Ton, // count - nano tons
StarGift, // count - stars
};
@ -155,7 +156,7 @@ struct GiftCode {
int starsUpgradedBySender = 0;
int limitedCount = 0;
int limitedLeft = 0;
int count = 0;
int64 count = 0;
GiftType type = GiftType::Premium;
bool viaGiveaway : 1 = false;
bool transferred : 1 = false;
@ -678,7 +679,7 @@ public:
not_null<HistoryItem*> parent,
not_null<PeerData*> from,
GiftType type,
int count);
int64 count);
MediaGiftBox(
not_null<HistoryItem*> parent,
not_null<PeerData*> from,

View file

@ -2245,7 +2245,7 @@ void MessageReactions::scheduleSendPaid(
_paid->scheduledPrivacySet = true;
}
if (count > 0) {
_item->history()->session().credits().lock(StarsAmount(count));
_item->history()->session().credits().lock(CreditsAmount(count));
}
_item->history()->owner().reactions().schedulePaid(_item);
}
@ -2259,7 +2259,7 @@ void MessageReactions::cancelScheduledPaid() {
if (_paid->scheduledFlag) {
if (const auto amount = int(_paid->scheduled)) {
_item->history()->session().credits().unlock(
StarsAmount(amount));
CreditsAmount(amount));
}
_paid->scheduled = 0;
_paid->scheduledFlag = 0;
@ -2322,9 +2322,9 @@ void MessageReactions::finishPaidSending(
if (const auto amount = send.count) {
const auto credits = &_item->history()->session().credits();
if (success) {
credits->withdrawLocked(StarsAmount(amount));
credits->withdrawLocked(CreditsAmount(amount));
} else {
credits->unlock(StarsAmount(amount));
credits->unlock(CreditsAmount(amount));
}
}
}

View file

@ -192,9 +192,18 @@ struct FullReplyTo {
struct SuggestPostOptions {
uint32 exists : 1 = 0;
uint32 stars : 31 = 0;
uint32 priceWhole : 31 = 0;
uint32 priceNano : 31 = 0;
uint32 ton : 1 = 0;
TimeId date = 0;
[[nodiscard]] CreditsAmount price() const {
return CreditsAmount(
priceWhole,
priceNano,
ton ? CreditsType::Ton : CreditsType::Stars);
}
explicit operator bool() const {
return exists != 0;
}

View file

@ -868,9 +868,8 @@ StarRefProgram ParseStarRefProgram(const MTPStarRefProgram *program) {
const auto &data = program->data();
result.commission = data.vcommission_permille().v;
result.durationMonths = data.vduration_months().value_or_empty();
result.revenuePerUser = data.vdaily_revenue_per_user()
? Data::FromTL(*data.vdaily_revenue_per_user())
: StarsAmount();
result.revenuePerUser = CreditsAmountFromTL(
data.vdaily_revenue_per_user());
result.endDate = data.vend_date().value_or_empty();
return result;
}

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "core/stars_amount.h"
#include "core/credits_amount.h"
#include "data/components/credits.h"
#include "data/data_birthday.h"
#include "data/data_peer.h"
@ -28,7 +28,7 @@ using DisallowedGiftTypes = base::flags<DisallowedGiftType>;
} // namespace Api
struct StarRefProgram {
StarsAmount revenuePerUser;
CreditsAmount revenuePerUser;
TimeId endDate = 0;
ushort commission = 0;
uint8 durationMonths = 0;

View file

@ -1681,11 +1681,21 @@ ServiceAction ParseServiceAction(
content.transactionId = data.vcharge().data().vid().v;
result.content = content;
}, [&](const MTPDmessageActionGiftStars &data) {
auto content = ActionGiftStars();
auto content = ActionGiftCredits();
content.cost = Ui::FillAmountAndCurrency(
data.vamount().v,
qs(data.vcurrency())).toUtf8();
content.credits = data.vstars().v;
content.amount = CreditsAmount(data.vstars().v, CreditsType::Stars);
result.content = content;
}, [&](const MTPDmessageActionGiftTon &data) {
auto content = ActionGiftCredits();
content.cost = Ui::FillAmountAndCurrency(
data.vamount().v,
qs(data.vcurrency())).toUtf8();
content.amount = CreditsAmount(
data.vamount().v / uint64(1'000'000'000),
data.vamount().v % uint64(1'000'000'000),
CreditsType::Ton);
result.content = content;
}, [&](const MTPDmessageActionPrizeStars &data) {
result.content = ActionPrizeStars{
@ -1761,7 +1771,7 @@ ServiceAction ParseServiceAction(
result.content = ActionSuggestedPostApproval{
.rejectComment = data.vreject_comment().value_or_empty(),
.scheduleDate = data.vschedule_date().value_or_empty(),
.stars = int(data.vstars_amount().value_or_empty()),
.price = CreditsAmountFromTL(data.vprice()),
.rejected = data.is_rejected(),
.balanceTooLow = data.is_balance_too_low(),
};

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "scheme.h"
#include "base/optional.h"
#include "base/variant.h"
#include "core/credits_amount.h"
#include "data/data_peer_id.h"
#include <QtCore/QSize>
@ -658,9 +659,9 @@ struct ActionPaymentRefunded {
Utf8String transactionId;
};
struct ActionGiftStars {
struct ActionGiftCredits {
Utf8String cost;
int credits = 0;
CreditsAmount amount;
};
struct ActionPrizeStars {
@ -701,7 +702,7 @@ struct ActionTodoAppendTasks {
struct ActionSuggestedPostApproval {
Utf8String rejectComment;
TimeId scheduleDate = 0;
int stars = 0;
CreditsAmount price;
bool rejected = false;
bool balanceTooLow = false;
};
@ -749,7 +750,7 @@ struct ServiceAction {
ActionGiveawayResults,
ActionBoostApply,
ActionPaymentRefunded,
ActionGiftStars,
ActionGiftCredits,
ActionPrizeStars,
ActionStarGift,
ActionPaidMessagesRefunded,

View file

@ -1353,16 +1353,16 @@ auto HtmlWriter::Wrap::pushMessage(
+ " refunded back "
+ amount;
return result;
}, [&](const ActionGiftStars &data) {
if (!data.credits || data.cost.isEmpty()) {
}, [&](const ActionGiftCredits &data) {
if (!data.amount || data.cost.isEmpty()) {
return serviceFrom + " sent you a gift.";
}
return serviceFrom
+ " sent you a gift for "
+ data.cost
+ ": "
+ QString::number(data.credits).toUtf8()
+ " Telegram Stars.";
+ QString::number(data.amount.value()).toUtf8()
+ (data.amount.ton() ? " TON." : " Telegram Stars.");
}, [&](const ActionPrizeStars &data) {
return "You won a prize in a giveaway organized by "
+ peers.wrapPeerName(data.peerId)
@ -1450,8 +1450,10 @@ auto HtmlWriter::Wrap::pushMessage(
return serviceFrom
+ (data.rejected ? " rejected " : " approved ")
+ "your suggested post"
+ (data.stars
? ", for " + QString::number(data.stars).toUtf8() + " stars"
+ (data.price
? (", for "
+ QString::number(data.price.value()).toUtf8()
+ (data.price.ton() ? " TON" : " stars"))
: "")
+ (data.scheduleDate
? (", "

View file

@ -644,14 +644,17 @@ QByteArray SerializeMessage(
pushBare("peer_name", wrapPeerName(data.peerId));
push("peer_id", data.peerId);
push("charge_id", data.transactionId);
}, [&](const ActionGiftStars &data) {
}, [&](const ActionGiftCredits &data) {
pushActor();
pushAction("send_stars_gift");
pushAction(data.amount.ton()
? "send_ton_gift"
: "send_stars_gift");
if (!data.cost.isEmpty()) {
push("cost", data.cost);
}
if (data.credits) {
push("stars", data.credits);
if (data.amount) {
push("amount_whole", data.amount.whole());
push("amount_nano", data.amount.nano());
}
}, [&](const ActionPrizeStars &data) {
pushActor();
@ -717,7 +720,9 @@ QByteArray SerializeMessage(
push("comment", data.rejectComment);
}
} else {
push("stars_amount", NumberToString(data.stars));
push("price_amount_whole", NumberToString(data.price.whole()));
push("price_amount_nano", NumberToString(data.price.nano()));
push("price_currency", data.price.ton() ? "TON" : "Stars");
push("scheduled_date", data.scheduleDate);
}
}, [](v::null_t) {});

View file

@ -1949,7 +1949,7 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
AddComponents(HistoryMessageSuggestedPost::Bit());
}
auto suggest = Get<HistoryMessageSuggestedPost>();
suggest->stars = edition.suggest.stars;
suggest->price = edition.suggest.price;
suggest->date = edition.suggest.date;
suggest->accepted = edition.suggest.accepted;
suggest->rejected = edition.suggest.rejected;
@ -4023,7 +4023,7 @@ void HistoryItem::createComponents(CreateConfig &&config) {
}
if (const auto suggest = Get<HistoryMessageSuggestedPost>()) {
suggest->stars = config.suggest.stars;
suggest->price = config.suggest.price;
suggest->date = config.suggest.date;
suggest->accepted = config.suggest.accepted;
suggest->rejected = config.suggest.rejected;
@ -4668,7 +4668,7 @@ void HistoryItem::createServiceFromMtp(const MTPDmessageService &message) {
const auto &data = action.c_messageActionSuggestedPostApproval();
UpdateComponents(HistoryServiceSuggestDecision::Bit());
const auto decision = Get<HistoryServiceSuggestDecision>();
decision->stars = data.vstars_amount().value_or_empty();
decision->price = CreditsAmountFromTL(data.vprice());
decision->balanceTooLow = data.is_balance_too_low();
decision->rejected = data.is_rejected();
decision->rejectComment = qs(data.vreject_comment().value_or_empty());
@ -5735,6 +5735,42 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
return result;
};
auto prepareGiftTon = [&](
const MTPDmessageActionGiftTon &action) {
auto result = PreparedServiceText();
const auto isSelf = (_from->id == _from->session().userPeerId());
const auto peer = isSelf ? _history->peer : _from;
const auto amount = action.vamount().v;
const auto currency = qs(action.vcurrency());
const auto cost = AmountAndStarCurrency(
&_history->session(),
amount,
currency);
const auto anonymous = _from->isServiceUser();
if (anonymous) {
result.text = tr::lng_action_gift_received_anonymous(
tr::now,
lt_cost,
cost,
Ui::Text::WithEntities);
} else {
result.links.push_back(peer->createOpenLink());
result.text = isSelf
? tr::lng_action_gift_sent(tr::now,
lt_cost,
cost,
Ui::Text::WithEntities)
: tr::lng_action_gift_received(
tr::now,
lt_user,
Ui::Text::Link(peer->shortName(), 1), // Link 1.
lt_cost,
cost,
Ui::Text::WithEntities);
}
return result;
};
auto prepareGiftPrize = [&](
const MTPDmessageActionPrizeStars &action) {
auto result = PreparedServiceText();
@ -6073,6 +6109,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
prepareBoostApply,
preparePaymentRefunded,
prepareGiftStars,
prepareGiftTon,
prepareGiftPrize,
prepareStarGift,
prepareStarGiftUnique,
@ -6194,6 +6231,12 @@ void HistoryItem::applyAction(const MTPMessageAction &action) {
_from,
Data::GiftType::Credits,
data.vstars().v);
}, [&](const MTPDmessageActionGiftTon &data) {
_media = std::make_unique<Data::MediaGiftBox>(
this,
_from,
Data::GiftType::Ton,
data.vamount().v);
}, [&](const MTPDmessageActionPrizeStars &data) {
_media = std::make_unique<Data::MediaGiftBox>(
this,

View file

@ -623,7 +623,7 @@ struct HistoryMessageFactcheck
struct HistoryMessageSuggestedPost
: RuntimeComponent<HistoryMessageSuggestedPost, HistoryItem> {
int stars = 0;
CreditsAmount price;
TimeId date = 0;
mtpRequestId requestId = 0;
bool accepted = false;
@ -701,7 +701,7 @@ struct HistoryServiceTodoAppendTasks
struct HistoryServiceSuggestDecision
: RuntimeComponent<HistoryServiceSuggestDecision, HistoryItem>
, HistoryServiceDependentData {
int stars = 0;
CreditsAmount price;
TimeId date = 0;
QString rejectComment;
bool rejected = false;

View file

@ -333,7 +333,7 @@ HistoryMessageSuggestInfo::HistoryMessageSuggestInfo(
return;
}
const auto &fields = data->data();
stars = fields.vstars_amount().v;
price = CreditsAmountFromTL(fields.vprice());
date = fields.vschedule_date().value_or_empty();
accepted = fields.is_accepted();
rejected = fields.is_rejected();
@ -350,7 +350,7 @@ HistoryMessageSuggestInfo::HistoryMessageSuggestInfo(
if (!options.exists) {
return;
}
stars = options.stars;
price = options.price();
date = options.date;
exists = true;
}

View file

@ -154,7 +154,7 @@ struct HistoryMessageSuggestInfo {
explicit HistoryMessageSuggestInfo(const Api::SendOptions &options);
explicit HistoryMessageSuggestInfo(SuggestPostOptions options);
int stars = 0;
CreditsAmount price;
TimeId date = 0;
bool accepted = false;
bool rejected = false;

View file

@ -78,7 +78,9 @@ void ChooseSuggestPriceBox(
wrap,
st::editTagField,
tr::lng_paid_cost_placeholder(),
args.value.stars ? QString::number(args.value.stars) : QString(),
(args.value.price()
? QString::number(args.value.price().value())
: QString()),
limit);
const auto field = owned.data();
wrap->widthValue() | rpl::start_with_next([=](int width) {
@ -137,14 +139,18 @@ void ChooseSuggestPriceBox(
Ui::AddDividerText(container, tr::lng_suggest_options_date_about());
AssertIsDebug()//tr::lng_suggest_options_offer
const auto save = [=] {
const auto now = uint32(field->getLastText().toULongLong());
const auto now = field->getLastText().toDouble();
if (now > limit) {
field->showError();
return;
}
const auto value = CreditsAmount(
int(std::floor(now)),
int(base::SafeRound((now - std::floor(now)) * 1'000'000'000.)));
args.done({
.exists = true,
.stars = now,
.priceWhole = uint32(value.whole()),
.priceNano = uint32(value.nano()),
.date = state->date.current(),
});
};
@ -234,15 +240,21 @@ void SuggestOptions::updateTexts() {
}
TextWithEntities SuggestOptions::composeText() const {
if (!_values.stars && !_values.date) {
if (!_values.price() && !_values.date) {
return tr::lng_suggest_bar_text(tr::now, Ui::Text::WithEntities);
} else if (!_values.date && _values.price().ton()) {
return tr::lng_suggest_bar_priced(AssertIsDebug()
tr::now,
lt_amount,
TextWithEntities{ Lang::FormatCreditsAmountDecimal(_values.price()) + " TON" },
Ui::Text::WithEntities);
} else if (!_values.date) {
return tr::lng_suggest_bar_priced(
tr::now,
lt_amount,
TextWithEntities{ QString::number(_values.stars) + " stars" },
TextWithEntities{ Lang::FormatCreditsAmountDecimal(_values.price()) + " stars" },
Ui::Text::WithEntities);
} else if (!_values.stars) {
} else if (!_values.price()) {
return tr::lng_suggest_bar_dated(
tr::now,
lt_date,
@ -250,11 +262,21 @@ TextWithEntities SuggestOptions::composeText() const {
langDateTime(base::unixtime::parse(_values.date)),
},
Ui::Text::WithEntities);
} else if (_values.price().ton()) {
return tr::lng_suggest_bar_priced_dated(
tr::now,
lt_amount,
TextWithEntities{ Lang::FormatCreditsAmountDecimal(_values.price()) + " TON," },
lt_date,
TextWithEntities{
langDateTime(base::unixtime::parse(_values.date)),
},
Ui::Text::WithEntities);
}
return tr::lng_suggest_bar_priced_dated(
tr::now,
lt_amount,
TextWithEntities{ QString::number(_values.stars) + " stars," },
TextWithEntities{ Lang::FormatCreditsAmountDecimal(_values.price()) + " stars," },
lt_date,
TextWithEntities{
langDateTime(base::unixtime::parse(_values.date)),

View file

@ -376,6 +376,10 @@ bool PremiumGift::gift() const {
return _data.slug.isEmpty() || !_data.channel;
}
bool PremiumGift::tonGift() const {
return (_data.type == Data::GiftType::Ton);
}
bool PremiumGift::starGift() const {
return (_data.type == Data::GiftType::StarGift);
}

View file

@ -52,6 +52,7 @@ public:
private:
[[nodiscard]] bool incomingGift() const;
[[nodiscard]] bool outgoingGift() const;
[[nodiscard]] bool tonGift() const;
[[nodiscard]] bool starGift() const;
[[nodiscard]] bool starGiftUpgrade() const;
[[nodiscard]] bool gift() const;

View file

@ -76,7 +76,7 @@ struct Changes {
if (wasSuggest->date != nowSuggest->date) {
result.date = true;
}
if (wasSuggest->stars != nowSuggest->stars) {
if (wasSuggest->price != nowSuggest->price) {
result.price = true;
}
const auto wasText = original->originalText();
@ -178,7 +178,7 @@ auto GenerateSuggestDecisionMedia(
fadedFg));
}
} else {
const auto stars = decision->stars;
const auto price = decision->price;
pushText(
TextWithEntities(
).append(Emoji(kAgreement)).append(' ').append(
@ -206,12 +206,16 @@ auto GenerateSuggestDecisionMedia(
date.time(),
QLocale::ShortFormat))),
Ui::Text::WithEntities)),
(stars
(price
? st::chatSuggestInfoMiddleMargin
: st::chatSuggestInfoLastMargin));
if (stars) {
const auto amount = Ui::Text::Bold(
tr::lng_prize_credits_amount(tr::now, lt_count, stars));
if (price) {
const auto amount = Ui::Text::Bold(price.ton()
? (Lang::FormatCreditsAmountDecimal(price) + u" TON"_q)
: tr::lng_prize_credits_amount(
tr::now,
lt_count_decimal,
price.value()));
pushText(
TextWithEntities(
).append(Emoji(kMoney)).append(' ').append(
@ -320,12 +324,14 @@ auto GenerateSuggestRequestMedia(
((changes && changes->price)
? tr::lng_suggest_change_price_label
: tr::lng_suggest_action_price_label)(tr::now),
Ui::Text::Bold(suggest->stars
? tr::lng_prize_credits_amount(
Ui::Text::Bold(!suggest->price
? tr::lng_suggest_action_price_free(tr::now)
: suggest->price.ton() AssertIsDebug()
? (Lang::FormatCreditsAmountDecimal(suggest->price) + u" TON"_q)
: tr::lng_prize_credits_amount(
tr::now,
lt_count,
suggest->stars)
: tr::lng_suggest_action_price_free(tr::now)),
suggest->price.value())),
});
entries.push_back({
((changes && changes->date)

View file

@ -135,8 +135,8 @@ void InnerWidget::fill() {
return _state.overallRevenue;
})
);
auto valueToString = [](StarsAmount v) {
return Lang::FormatStarsAmountDecimal(v);
auto valueToString = [](CreditsAmount v) {
return Lang::FormatCreditsAmountDecimal(v);
};
if (data.revenueGraph.chart) {
@ -161,7 +161,7 @@ void InnerWidget::fill() {
Ui::AddSkip(container, st::channelEarnOverviewTitleSkip);
const auto addOverview = [&](
rpl::producer<StarsAmount> value,
rpl::producer<CreditsAmount> value,
const tr::phrase<> &text) {
const auto line = container->add(
Ui::CreateSkipWidget(container, 0),
@ -177,8 +177,10 @@ void InnerWidget::fill() {
line,
std::move(
value
) | rpl::map([=](StarsAmount v) {
return v ? ToUsd(v, multiplier, kMinorLength) : QString();
) | rpl::map([=](CreditsAmount v) {
return v
? ToUsd(v, multiplier, kMinorLength)
: QString();
}),
st::channelEarnOverviewSubMinorLabel);
rpl::combine(
@ -254,7 +256,7 @@ void InnerWidget::fill() {
(peer()->isSelf()
? rpl::duplicate(overallBalanceValue) | rpl::type_erased()
: rpl::duplicate(availableBalanceValue)
) | rpl::map([=](StarsAmount v) {
) | rpl::map([=](CreditsAmount v) {
return v ? ToUsd(v, multiplier, kMinorLength) : QString();
}));
container->resizeToWidth(container->width());

View file

@ -603,7 +603,7 @@ object_ptr<Ui::BoxContent> JoinStarRefBox(
const auto layout = box->verticalLayout();
const auto session = &initialRecipient->session();
auto text = Ui::Text::Colorized(Ui::CreditsEmoji(session));
text.append(Lang::FormatStarsAmountRounded(average));
text.append(Lang::FormatCreditsAmountRounded(average));
layout->add(
object_ptr<Ui::FlatLabel>(
box,

View file

@ -50,11 +50,11 @@ QString ToUsd(
Data::EarnInt value,
float64 rate,
int afterFloat) {
return ToUsd(StarsAmount(value), rate, afterFloat);
return ToUsd(CreditsAmount(value), rate, afterFloat);
}
QString ToUsd(
StarsAmount value,
CreditsAmount value,
float64 rate,
int afterFloat) {
constexpr auto kApproximately = QChar(0x2248);

View file

@ -18,7 +18,7 @@ namespace Info::ChannelEarn {
float64 rate,
int afterFloat);
[[nodiscard]] QString ToUsd(
StarsAmount value,
CreditsAmount value,
float64 rate,
int afterFloat);

View file

@ -258,9 +258,9 @@ void InnerWidget::load() {
}
const auto &data = d.vstatus().data();
auto &e = _state.creditsEarn;
e.currentBalance = Data::FromTL(data.vcurrent_balance());
e.availableBalance = Data::FromTL(data.vavailable_balance());
e.overallRevenue = Data::FromTL(data.voverall_revenue());
e.currentBalance = CreditsAmountFromTL(data.vcurrent_balance());
e.availableBalance = CreditsAmountFromTL(data.vavailable_balance());
e.overallRevenue = CreditsAmountFromTL(data.voverall_revenue());
e.isWithdrawalEnabled = data.is_withdrawal_enabled();
e.nextWithdrawalAt = data.vnext_withdrawal_at()
? base::unixtime::parse(
@ -395,7 +395,7 @@ void InnerWidget::fill() {
//constexpr auto kApproximately = QChar(0x2248);
const auto multiplier = data.usdRate;
const auto creditsToUsdMap = [=](StarsAmount c) {
const auto creditsToUsdMap = [=](CreditsAmount c) {
const auto creditsMultiplier = _state.creditsEarn.usdRate
* Data::kEarnMultiplier;
return c ? ToUsd(c, creditsMultiplier, 0) : QString();
@ -707,7 +707,7 @@ void InnerWidget::fill() {
const auto addOverview = [&](
rpl::producer<EarnInt> currencyValue,
rpl::producer<StarsAmount> creditsValue,
rpl::producer<CreditsAmount> creditsValue,
const tr::phrase<> &text,
bool showCurrency,
bool showCredits) {
@ -741,8 +741,10 @@ void InnerWidget::fill() {
const auto creditsLabel = Ui::CreateChild<Ui::FlatLabel>(
line,
rpl::duplicate(creditsValue) | rpl::map([](StarsAmount value) {
return Lang::FormatStarsAmountDecimal(value);
rpl::duplicate(
creditsValue
) | rpl::map([](CreditsAmount value) {
return Lang::FormatCreditsAmountDecimal(value);
}),
st::channelEarnOverviewMajorLabel);
const auto icon = Ui::CreateSingleStarWidget(
@ -761,7 +763,7 @@ void InnerWidget::fill() {
int available,
const QSize &size,
const QSize &creditsSize,
StarsAmount credits) {
CreditsAmount credits) {
const auto skip = st::channelEarnOverviewSubMinorLabelPos.x();
line->resize(line->width(), size.height());
minorLabel->moveToLeft(

View file

@ -940,19 +940,20 @@ rpl::producer<uint64> AddCurrencyAction(
return state->balance.value();
}
rpl::producer<StarsAmount> AddCreditsAction(
rpl::producer<CreditsAmount> AddCreditsAction(
not_null<UserData*> user,
not_null<Ui::VerticalLayout*> wrap,
not_null<Controller*> controller) {
struct State final {
rpl::variable<StarsAmount> balance;
rpl::variable<CreditsAmount> balance;
};
const auto state = wrap->lifetime().make_state<State>();
const auto parentController = controller->parentController();
const auto wrapButton = AddActionButton(
wrap,
tr::lng_manage_peer_bot_balance_credits(),
state->balance.value() | rpl::map(rpl::mappers::_1 > StarsAmount(0)),
state->balance.value(
) | rpl::map(rpl::mappers::_1 > CreditsAmount(0)),
[=] { parentController->showSection(Info::BotEarn::Make(user)); },
nullptr);
{
@ -992,7 +993,7 @@ rpl::producer<StarsAmount> AddCreditsAction(
) | rpl::start_with_next([=, &st](
int width,
const QString &button,
StarsAmount balance) {
CreditsAmount balance) {
const auto available = width
- rect::m::sum::h(st.padding)
- st.style.font->width(button)
@ -1000,7 +1001,7 @@ rpl::producer<StarsAmount> AddCreditsAction(
name->setMarkedText(
base::duplicate(icon)
.append(QChar(' '))
.append(Lang::FormatStarsAmountDecimal(balance)),
.append(Lang::FormatCreditsAmountDecimal(balance)),
Core::TextContext({
.session = &user->session(),
.repaint = [=] { name->update(); },
@ -2404,7 +2405,7 @@ void ActionsFiller::addBalanceActions(not_null<UserData*> user) {
std::move(currencyBalance),
std::move(creditsBalance)
) | rpl::map((rpl::mappers::_1 > 0)
|| (rpl::mappers::_2 > StarsAmount(0))));
|| (rpl::mappers::_2 > CreditsAmount(0))));
}
void ActionsFiller::addInviteToGroupAction(not_null<UserData*> user) {

View file

@ -927,7 +927,7 @@ void CreditsRow::init() {
st::semiboldTextStyle,
TextWithEntities()
.append(_entry.in ? QChar('+') : kMinus)
.append(Lang::FormatStarsAmountDecimal(_entry.credits.abs()))
.append(Lang::FormatCreditsAmountDecimal(_entry.credits.abs()))
.append(QChar(' '))
.append(manager.creditsEmoji()),
kMarkupTextOptions,

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "lang/lang_tag.h"
#include "core/stars_amount.h"
#include "core/credits_amount.h"
#include "lang/lang_keys.h"
#include "ui/text/text.h"
#include "base/qt/qt_common_adapters.h"
@ -952,18 +952,18 @@ QString FormatExactCountDecimal(float64 number) {
return QLocale().toString(number, 'f', QLocale::FloatingPointShortest);
}
ShortenedCount FormatStarsAmountToShort(StarsAmount amount) {
ShortenedCount FormatCreditsAmountToShort(CreditsAmount amount) {
const auto attempt = FormatCountToShort(amount.whole());
return attempt.shortened ? attempt : ShortenedCount{
.string = FormatStarsAmountDecimal(amount),
.string = FormatCreditsAmountDecimal(amount),
};
}
QString FormatStarsAmountDecimal(StarsAmount amount) {
QString FormatCreditsAmountDecimal(CreditsAmount amount) {
return FormatExactCountDecimal(amount.value());
}
QString FormatStarsAmountRounded(StarsAmount amount) {
QString FormatCreditsAmountRounded(CreditsAmount amount) {
const auto value = amount.value();
return FormatExactCountDecimal(base::SafeRound(value * 100.) / 100.);
}

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
class StarsAmount;
class CreditsAmount;
enum lngtag_count : int;
@ -29,9 +29,10 @@ struct ShortenedCount {
[[nodiscard]] ShortenedCount FormatCountToShort(int64 number);
[[nodiscard]] QString FormatCountDecimal(int64 number);
[[nodiscard]] QString FormatExactCountDecimal(float64 number);
[[nodiscard]] ShortenedCount FormatStarsAmountToShort(StarsAmount amount);
[[nodiscard]] QString FormatStarsAmountDecimal(StarsAmount amount);
[[nodiscard]] QString FormatStarsAmountRounded(StarsAmount amount);
[[nodiscard]] ShortenedCount FormatCreditsAmountToShort(
CreditsAmount amount);
[[nodiscard]] QString FormatCreditsAmountDecimal(CreditsAmount amount);
[[nodiscard]] QString FormatCreditsAmountRounded(CreditsAmount amount);
struct PluralResult {
int keyShift = 0;

View file

@ -192,7 +192,8 @@ messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags
messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector<Peer> = MessageAction;
messageActionTodoCompletions#cc7c5c89 completed:Vector<int> incompleted:Vector<int> = MessageAction;
messageActionTodoAppendTasks#c7edbc83 list:Vector<TodoItem> = MessageAction;
messageActionSuggestedPostApproval#af42ae29 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int stars_amount:flags.4?long = MessageAction;
messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction;
messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -1925,6 +1926,7 @@ payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector<Connected
payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector<StarRefProgram> users:Vector<User> next_offset:flags.0?string = payments.SuggestedStarRefBots;
starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount;
starsTonAmount#74aee3e0 amount:long = StarsAmount;
messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers;
messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector<Document> = messages.FoundStickers;
@ -1994,7 +1996,7 @@ todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:fla
todoCompletion#4cc120b7 id:int completed_by:long date:int = TodoCompletion;
suggestedPost#95ee6a6d flags:# accepted:flags.1?true rejected:flags.2?true stars_amount:long schedule_date:flags.0?int = SuggestedPost;
suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost;
---functions---
@ -2571,8 +2573,8 @@ payments.applyGiftCode#f6e26854 slug:string = Updates;
payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo;
payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates;
payments.getStarsTopupOptions#c00ec7d3 = Vector<StarsTopupOption>;
payments.getStarsStatus#104fcfa7 peer:InputPeer = payments.StarsStatus;
payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus;
payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus;
payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus;
payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult;
payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates;
payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true peer:InputPeer = payments.StarsRevenueStats;

View file

@ -631,7 +631,7 @@ void Form::processReceipt(const MTPDpayments_paymentReceiptStars &data) {
ImageLocation())
: nullptr,
.peerId = peerFromUser(data.vbot_id().v),
.credits = StarsAmount(data.vtotal_amount().v),
.credits = CreditsAmount(data.vtotal_amount().v),
.date = data.vdate().v,
};
_updates.fire(CreditsReceiptReady{ .data = receiptData });

View file

@ -211,7 +211,7 @@ struct CreditsReceiptData {
QString description;
PhotoData *photo = nullptr;
PeerId peerId = PeerId(0);
StarsAmount credits;
CreditsAmount credits;
TimeId date = 0;
};

View file

@ -33,7 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Settings {
[[nodiscard]] not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
rpl::producer<StarsAmount> balanceValue,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue = nullptr);
} // namespace Settings

View file

@ -41,7 +41,7 @@ struct PaidReactionBoxArgs {
QString channel;
Fn<rpl::producer<TextWithContext>(rpl::producer<int> amount)> submit;
rpl::producer<StarsAmount> balanceValue;
rpl::producer<CreditsAmount> balanceValue;
Fn<void(int, uint64)> send;
};

View file

@ -405,7 +405,7 @@ void Credits::setupContent() {
const auto balanceAmount = Ui::CreateChild<Ui::FlatLabel>(
balanceLine,
_controller->session().credits().balanceValue(
) | rpl::map(Lang::FormatStarsAmountDecimal),
) | rpl::map(Lang::FormatCreditsAmountDecimal),
st::creditsSettingsBigBalance);
balanceAmount->sizeValue() | rpl::start_with_next([=] {
balanceLine->resize(
@ -718,7 +718,7 @@ Fn<void()> BuyStarsHandler::handler(
const auto options = _api
? _api->options()
: Data::CreditTopupOptions();
const auto amount = StarsAmount();
const auto amount = CreditsAmount();
const auto weak = Ui::MakeWeak(box);
FillCreditOptions(show, inner, self, amount, [=] {
if (const auto strong = weak.data()) {

View file

@ -141,13 +141,13 @@ class Balance final
public:
using Ui::RpWidget::RpWidget;
void setBalance(StarsAmount balance) {
void setBalance(CreditsAmount balance) {
_balance = balance;
_tooltip = Lang::FormatStarsAmountDecimal(balance);
_tooltip = Lang::FormatCreditsAmountDecimal(balance);
}
void enterEventHook(QEnterEvent *e) override {
if (_balance >= StarsAmount(10'000)) {
if (_balance >= CreditsAmount(10'000)) {
Ui::Tooltip::Show(1000, this);
}
}
@ -170,7 +170,7 @@ public:
private:
QString _tooltip;
StarsAmount _balance;
CreditsAmount _balance;
};
@ -506,7 +506,7 @@ void FillCreditOptions(
std::shared_ptr<Main::SessionShow> show,
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
StarsAmount minimumCredits,
CreditsAmount minimumCredits,
Fn<void()> paid,
rpl::producer<QString> subtitle,
std::vector<Data::CreditTopupOption> preloadedTopupOptions) {
@ -552,12 +552,12 @@ void FillCreditOptions(
- int(singleStarWidth * 1.5);
const auto buttonHeight = st.height + rect::m::sum::v(st.padding);
const auto minCredits = (!options.empty()
&& (minimumCredits > StarsAmount(options.back().credits)))
? StarsAmount()
&& (minimumCredits > CreditsAmount(options.back().credits)))
? CreditsAmount()
: minimumCredits;
for (auto i = 0; i < options.size(); i++) {
const auto &option = options[i];
if (StarsAmount(option.credits) < minCredits) {
if (CreditsAmount(option.credits) < minCredits) {
continue;
}
const auto button = [&] {
@ -684,7 +684,7 @@ void FillCreditOptions(
not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
rpl::producer<StarsAmount> balanceValue,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue) {
struct State final {
@ -720,10 +720,10 @@ not_null<Ui::RpWidget*> AddBalanceWidget(
};
std::move(
balanceValue
) | rpl::start_with_next([=](StarsAmount value) {
) | rpl::start_with_next([=](CreditsAmount value) {
state->count.setText(
st::semiboldTextStyle,
Lang::FormatStarsAmountToShort(value).string);
Lang::FormatCreditsAmountToShort(value).string);
balance->setBalance(value);
resize();
}, balance->lifetime());
@ -1468,7 +1468,7 @@ void GenericCreditsEntryBox(
: (e.gift && !creditsHistoryStarGift)
? QString()
: QString(kMinus))
.append(Lang::FormatStarsAmountDecimal(e.credits.abs()))
.append(Lang::FormatCreditsAmountDecimal(e.credits.abs()))
.append(QChar(' '))
.append(owner->customEmojiManager().creditsEmoji());
text->setMarkedText(
@ -2069,7 +2069,7 @@ void GiftedCreditsBox(
? tr::lng_credits_box_history_entry_gift_name
: tr::lng_credits_box_history_entry_gift_sent)(tr::now),
.date = base::unixtime::parse(date),
.credits = StarsAmount(count),
.credits = CreditsAmount(count),
.bareMsgId = uint64(),
.barePeerId = (anonymous ? uint64() : peer->id.value),
.peerType = (anonymous ? PeerType::Fragment : PeerType::Peer),
@ -2092,7 +2092,7 @@ void CreditsPrizeBox(
.title = QString(),
.description = TextWithEntities(),
.date = base::unixtime::parse(date),
.credits = StarsAmount(data.count),
.credits = CreditsAmount(data.count),
.barePeerId = data.channel
? data.channel->id.value
: 0,
@ -2115,7 +2115,7 @@ void GlobalStarGiftBox(
box,
show,
Data::CreditsHistoryEntry{
.credits = StarsAmount(data.stars),
.credits = CreditsAmount(data.stars),
.bareGiftStickerId = data.document->id,
.bareGiftOwnerId = ownerId,
.bareGiftResaleRecipientId = ((resaleRecipientId != selfId)
@ -2142,7 +2142,7 @@ Data::CreditsHistoryEntry SavedStarGiftEntry(
return {
.description = data.message,
.date = base::unixtime::parse(data.date),
.credits = StarsAmount(data.info.stars),
.credits = CreditsAmount(data.info.stars),
.bareMsgId = uint64(data.manageId.userMessageId().bare),
.barePeerId = data.fromId.value,
.bareGiftStickerId = data.info.document->id,
@ -2221,7 +2221,7 @@ void StarGiftViewBox(
.id = data.slug,
.description = data.message,
.date = base::unixtime::parse(item->date()),
.credits = StarsAmount(data.count),
.credits = CreditsAmount(data.count),
.bareMsgId = uint64(item->id.bare),
.barePeerId = fromId.value,
.bareGiftStickerId = data.document ? data.document->id : 0,
@ -2272,7 +2272,7 @@ void ShowRefundInfoBox(
auto info = Data::CreditsHistoryEntry();
info.id = refund->transactionId;
info.date = base::unixtime::parse(item->date());
info.credits = StarsAmount(refund->amount);
info.credits = CreditsAmount(refund->amount);
info.barePeerId = refund->peer->id.value;
info.peerType = Data::CreditsHistoryEntry::PeerType::Peer;
info.refunded = true;
@ -2370,7 +2370,7 @@ void SmallBalanceBox(
Fn<void()> paid) {
Expects(show->session().credits().loaded());
auto credits = StarsAmount(wholeCredits);
auto credits = CreditsAmount(wholeCredits);
box->setWidth(st::boxWideWidth);
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
@ -2399,8 +2399,8 @@ void SmallBalanceBox(
});
auto needed = show->session().credits().balanceValue(
) | rpl::map([=](StarsAmount balance) {
return (balance < credits) ? (credits - balance) : StarsAmount();
) | rpl::map([=](CreditsAmount balance) {
return (balance < credits) ? (credits - balance) : CreditsAmount();
});
const auto content = [&]() -> Ui::Premium::TopBarAbstract* {
return box->setPinnedToTopContent(object_ptr<Ui::Premium::TopBar>(
@ -2412,8 +2412,8 @@ void SmallBalanceBox(
rpl::duplicate(
needed
) | rpl::filter(
rpl::mappers::_1 > StarsAmount(0)
) | rpl::map([](StarsAmount amount) {
rpl::mappers::_1 > CreditsAmount(0)
) | rpl::map([](CreditsAmount amount) {
return amount.value();
})),
.about = (v::is<SmallBalanceSubscription>(source)
@ -2507,7 +2507,7 @@ void AddWithdrawalWidget(
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
rpl::producer<QString> secondButtonUrl,
rpl::producer<StarsAmount> availableBalanceValue,
rpl::producer<CreditsAmount> availableBalanceValue,
rpl::producer<QDateTime> dateValue,
bool withdrawalEnabled,
rpl::producer<QString> usdValue) {
@ -2522,8 +2522,8 @@ void AddWithdrawalWidget(
labels,
rpl::duplicate(
availableBalanceValue
) | rpl::map([](StarsAmount v) {
return Lang::FormatStarsAmountDecimal(v);
) | rpl::map([](CreditsAmount v) {
return Lang::FormatCreditsAmountDecimal(v);
}),
st::channelEarnBalanceMajorLabel);
const auto icon = Ui::CreateSingleStarWidget(
@ -2622,7 +2622,7 @@ void AddWithdrawalWidget(
st::settingsPremiumIconStar,
{ 0, -st::moderateBoxExpandInnerSkip, 0, 0 },
true));
using Balance = rpl::variable<StarsAmount>;
using Balance = rpl::variable<CreditsAmount>;
const auto currentBalance = input->lifetime().make_state<Balance>(
rpl::duplicate(availableBalanceValue));
const auto process = [=] {
@ -2834,7 +2834,7 @@ void MaybeRequestBalanceIncrease(
state->lifetime.destroy();
const auto balance = session->credits().balance();
if (StarsAmount(credits) <= balance) {
if (CreditsAmount(credits) <= balance) {
if (const auto onstack = done) {
onstack(SmallBalanceResult::Already);
}

View file

@ -72,14 +72,14 @@ void FillCreditOptions(
std::shared_ptr<Main::SessionShow> show,
not_null<Ui::VerticalLayout*> container,
not_null<PeerData*> peer,
StarsAmount minCredits,
CreditsAmount minCredits,
Fn<void()> paid,
rpl::producer<QString> subtitle,
std::vector<Data::CreditTopupOption> preloadedTopupOptions);
[[nodiscard]] not_null<Ui::RpWidget*> AddBalanceWidget(
not_null<Ui::RpWidget*> parent,
rpl::producer<StarsAmount> balanceValue,
rpl::producer<CreditsAmount> balanceValue,
bool rightAlign,
rpl::producer<float64> opacityValue = nullptr);
@ -88,7 +88,7 @@ void AddWithdrawalWidget(
not_null<Window::SessionController*> controller,
not_null<PeerData*> peer,
rpl::producer<QString> secondButtonUrl,
rpl::producer<StarsAmount> availableBalanceValue,
rpl::producer<CreditsAmount> availableBalanceValue,
rpl::producer<QDateTime> dateValue,
bool withdrawalEnabled,
rpl::producer<QString> usdValue);

View file

@ -738,9 +738,9 @@ void SetupPremium(
container,
tr::lng_settings_credits(),
controller->session().credits().balanceValue(
) | rpl::map([=](StarsAmount c) {
) | rpl::map([=](CreditsAmount c) {
return c
? Lang::FormatStarsAmountToShort(c).string
? Lang::FormatCreditsAmountToShort(c).string
: QString();
}),
st::settingsButton),

View file

@ -134,7 +134,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/palette.h"
#include "styles/style_basic.h"
#include "core/stars_amount.h"
#include "core/credits_amount.h"
#include "core/utils.h"
#include "logs.h"
#include "config.h"

View file

@ -136,6 +136,33 @@ auto EmptyMessageDraftSources()
return cWorkingDir() + u"tdata/tdld/"_q;
}
[[nodiscard]] std::pair<quint64, quint64> SerializeSuggest(
SuggestPostOptions options) {
return {
((quint64(options.exists) << 63)
| (quint64(quint32(options.date)))),
((quint64(options.ton) << 63)
| (quint64(options.priceWhole) << 32)
| (quint64(options.priceNano))),
};
}
[[nodiscard]] SuggestPostOptions DeserializeSuggest(
std::pair<quint64, quint64> suggest) {
const auto exists = (suggest.first >> 63) ? 1 : 0;
const auto date = TimeId(uint32(suggest.first & 0xFFFF'FFFFULL));
const auto ton = (suggest.second >> 63) ? 1 : 0;
const auto priceWhole = uint32((suggest.second >> 32) & 0x7FFF'FFFFULL);
const auto priceNano = uint32(suggest.second & 0xFFFF'FFFFULL);
return {
.exists = uint32(exists),
.priceWhole = priceWhole,
.priceNano = priceNano,
.ton = uint32(ton),
.date = date,
};
}
} // namespace
Account::Account(not_null<Main::Account*> owner, const QString &dataName)
@ -1276,7 +1303,7 @@ void Account::writeDrafts(not_null<History*> history) {
+ Serialize::stringSize(text.text)
+ TextUtilities::SerializeTagsSize(text.tags)
+ sizeof(qint64) + sizeof(qint64) // messageId
+ sizeof(quint64) // suggest
+ (sizeof(quint64) * 2) // suggest
+ Serialize::stringSize(webpage.url)
+ sizeof(qint32) // webpage.forceLargeMedia
+ sizeof(qint32) // webpage.forceSmallMedia
@ -1303,15 +1330,15 @@ void Account::writeDrafts(not_null<History*> history) {
const TextWithTags &text,
const Data::WebPageDraft &webpage,
auto&&) { // cursor
const auto serialized = SerializeSuggest(suggest);
data.stream
<< key.serialize()
<< text.text
<< TextUtilities::SerializeTags(text.tags)
<< qint64(reply.messageId.peer.value)
<< qint64(reply.messageId.msg.bare)
<< quint64(quint64(quint32(suggest.date))
| (quint64(suggest.stars) << 32)
| (quint64(suggest.exists) << 63))
<< serialized.first
<< serialized.second
<< webpage.url
<< qint32(webpage.forceLargeMedia ? 1 : 0)
<< qint32(webpage.forceSmallMedia ? 1 : 0)
@ -1536,7 +1563,7 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
QByteArray textTagsSerialized;
qint64 keyValue = 0;
qint64 messageIdPeer = 0, messageIdMsg = 0;
quint64 suggestSerialized = 0;
std::pair<quint64, quint64> suggestSerialized;
qint32 keyValueOld = 0;
QString webpageUrl;
qint32 webpageForceLargeMedia = 0;
@ -1572,7 +1599,9 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
>> messageIdPeer
>> messageIdMsg;
if (withSuggest) {
draft.stream >> suggestSerialized;
draft.stream
>> suggestSerialized.first
>> suggestSerialized.second;
}
draft.stream
>> webpageUrl
@ -1597,13 +1626,7 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
MsgId(messageIdMsg)),
.topicRootId = key.topicRootId(),
},
SuggestPostOptions{
.exists = uint32(suggestSerialized >> 63),
.stars = uint32(
(suggestSerialized & ~(1ULL << 63)) >> 32),
.date = TimeId(
uint32(suggestSerialized & 0xFFFF'FFFFULL)),
},
DeserializeSuggest(suggestSerialized),
MessageCursor(),
Data::WebPageDraft{
.url = webpageUrl,

View file

@ -164,11 +164,11 @@ not_null<RpWidget*> CreateSingleStarWidget(
not_null<MaskedInputField*> AddInputFieldForCredits(
not_null<VerticalLayout*> container,
rpl::producer<StarsAmount> value) {
rpl::producer<CreditsAmount> value) {
const auto &st = st::botEarnInputField;
const auto inputContainer = container->add(
CreateSkipWidget(container, st.heightMin));
const auto currentValue = rpl::variable<StarsAmount>(
const auto currentValue = rpl::variable<CreditsAmount>(
rpl::duplicate(value));
const auto input = CreateChild<NumberInput>(
inputContainer,
@ -178,7 +178,7 @@ not_null<MaskedInputField*> AddInputFieldForCredits(
currentValue.current().whole());
rpl::duplicate(
value
) | rpl::start_with_next([=](StarsAmount v) {
) | rpl::start_with_next([=](CreditsAmount v) {
input->changeLimit(v.whole());
input->setText(QString::number(v.whole()));
}, input->lifetime());

View file

@ -44,7 +44,7 @@ using PaintRoundImageCallback = Fn<void(
[[nodiscard]] not_null<Ui::MaskedInputField*> AddInputFieldForCredits(
not_null<Ui::VerticalLayout*> container,
rpl::producer<StarsAmount> value);
rpl::producer<CreditsAmount> value);
PaintRoundImageCallback GenerateCreditsPaintUserpicCallback(
const Data::CreditsHistoryEntry &entry);

View file

@ -34,7 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "core/stars_amount.h"
#include "core/credits_amount.h"
#include "ui/arc_angles.h"
#include "ui/text/text.h"