diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 3800886afa..d36f0213fa 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -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 diff --git a/Telegram/SourceFiles/api/api_common.cpp b/Telegram/SourceFiles/api/api_common.cpp index 29617a3f16..65ec607c04 100644 --- a/Telegram/SourceFiles/api/api_common.cpp +++ b/Telegram/SourceFiles/api/api_common.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/api/api_credits.cpp b/Telegram/SourceFiles/api/api_credits.cpp index ec49947ebf..cda8180343 100644 --- a/Telegram/SourceFiles/api/api_credits.cpp +++ b/Telegram/SourceFiles/api/api_credits.cpp @@ -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 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() diff --git a/Telegram/SourceFiles/api/api_suggest_post.cpp b/Telegram/SourceFiles/api/api_suggest_post.cpp index a6a1f09379..b6a04474d3 100644 --- a/Telegram/SourceFiles/api/api_suggest_post.cpp +++ b/Telegram/SourceFiles/api/api_suggest_post.cpp @@ -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 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, diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index d2a19a7420..7b0c538850 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -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( diff --git a/Telegram/SourceFiles/boxes/gift_credits_box.cpp b/Telegram/SourceFiles/boxes/gift_credits_box.cpp index 761b387e53..8df343cec4 100644 --- a/Telegram/SourceFiles/boxes/gift_credits_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_credits_box.cpp @@ -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(), {}); diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index cb5dee6e26..0b898a86ee 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -411,7 +411,7 @@ void AddTableRow( table->st().defaultValue.style.font->height); const auto label = Ui::CreateChild( 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(), diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 2cae756a63..16c8cae875 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -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(); 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); }); } { diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index d021cba69f..1a6827043b 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -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(), diff --git a/Telegram/SourceFiles/core/credits_amount.h b/Telegram/SourceFiles/core/credits_amount.h new file mode 100644 index 0000000000..1704e28161 --- /dev/null +++ b/Telegram/SourceFiles/core/credits_amount.h @@ -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 +class boxed; +} // namespace tl + +using MTPStarsAmount = tl::boxed; + +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); diff --git a/Telegram/SourceFiles/core/stars_amount.h b/Telegram/SourceFiles/core/stars_amount.h deleted file mode 100644 index ca0e6fbe2d..0000000000 --- a/Telegram/SourceFiles/core/stars_amount.h +++ /dev/null @@ -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; -} diff --git a/Telegram/SourceFiles/data/components/credits.cpp b/Telegram/SourceFiles/data/components/credits.cpp index 119847e0fc..5f93ba303c 100644 --- a/Telegram/SourceFiles/data/components/credits.cpp +++ b/Telegram/SourceFiles/data/components/credits.cpp @@ -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 session) : _session(session) , _reload([=] { load(true); }) { @@ -32,7 +27,7 @@ Credits::Credits(not_null session) Credits::~Credits() = default; void Credits::apply(const MTPDupdateStarsBalance &data) { - apply(FromTL(data.vbalance())); + apply(CreditsAmountFromTL(data.vbalance())); } rpl::producer Credits::rateValue( @@ -80,13 +75,13 @@ rpl::producer 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 Credits::balanceValue() const { +rpl::producer 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())); +} diff --git a/Telegram/SourceFiles/data/components/credits.h b/Telegram/SourceFiles/data/components/credits.h index dac6df8981..000df652e3 100644 --- a/Telegram/SourceFiles/data/components/credits.h +++ b/Telegram/SourceFiles/data/components/credits.h @@ -13,23 +13,21 @@ class Session; namespace Data { -[[nodiscard]] StarsAmount FromTL(const MTPStarsAmount &value); - class Credits final { public: explicit Credits(not_null 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 loadedValue() const; - [[nodiscard]] StarsAmount balance() const; - [[nodiscard]] StarsAmount balance(PeerId peerId) const; - [[nodiscard]] rpl::producer balanceValue() const; + [[nodiscard]] CreditsAmount balance() const; + [[nodiscard]] CreditsAmount balance(PeerId peerId) const; + [[nodiscard]] rpl::producer balanceValue() const; [[nodiscard]] rpl::producer rateValue( not_null 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 _loader; - base::flat_map _cachedPeerBalances; + base::flat_map _cachedPeerBalances; base::flat_map _cachedPeerCurrencyBalances; - StarsAmount _balance; - StarsAmount _locked; - rpl::variable _nonLockedBalance; + CreditsAmount _balance; + CreditsAmount _locked; + rpl::variable _nonLockedBalance; rpl::event_stream<> _loadedChanges; crl::time _lastLoaded = 0; float64 _rate = 0.; diff --git a/Telegram/SourceFiles/data/data_credits.h b/Telegram/SourceFiles/data/data_credits.h index 0432097980..3a3c7e77f3 100644 --- a/Telegram/SourceFiles/data/data_credits.h +++ b/Telegram/SourceFiles/data/data_credits.h @@ -59,7 +59,7 @@ struct CreditsHistoryEntry final { QDateTime lastSaleDate; PhotoId photoId = 0; std::vector 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; Fn()> 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 list; std::vector subscriptions; - StarsAmount balance; + CreditsAmount balance; uint64 subscriptionsMissingBalance = 0; bool allLoaded = false; OffsetToken token; diff --git a/Telegram/SourceFiles/data/data_credits_earn.h b/Telegram/SourceFiles/data/data_credits_earn.h index e26e2bebc0..af1d840c72 100644 --- a/Telegram/SourceFiles/data/data_credits_earn.h +++ b/Telegram/SourceFiles/data/data_credits_earn.h @@ -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 @@ -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; diff --git a/Telegram/SourceFiles/data/data_drafts.cpp b/Telegram/SourceFiles/data/data_drafts.cpp index 5a61b486e8..9aae0e8bb0 100644 --- a/Telegram/SourceFiles/data/data_drafts.cpp +++ b/Telegram/SourceFiles/data/data_drafts.cpp @@ -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 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( textWithTags, diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index e4fc70bf56..3fb17b5c44 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -2514,7 +2514,7 @@ MediaGiftBox::MediaGiftBox( not_null parent, not_null from, GiftType type, - int count) + int64 count) : MediaGiftBox(parent, from, GiftCode{ .count = count, .type = type }) { } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 7f0e172306..dab3e57b2e 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -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 parent, not_null from, GiftType type, - int count); + int64 count); MediaGiftBox( not_null parent, not_null from, diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index fec98a7920..a909a2c4cd 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -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)); } } } diff --git a/Telegram/SourceFiles/data/data_msg_id.h b/Telegram/SourceFiles/data/data_msg_id.h index f093a6f2ef..bee8324194 100644 --- a/Telegram/SourceFiles/data/data_msg_id.h +++ b/Telegram/SourceFiles/data/data_msg_id.h @@ -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; } diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index f7abd8d9f0..7dfd473d52 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -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; } diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 5e57eaef90..a47340132f 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -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; } // namespace Api struct StarRefProgram { - StarsAmount revenuePerUser; + CreditsAmount revenuePerUser; TimeId endDate = 0; ushort commission = 0; uint8 durationMonths = 0; diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 52d79e4079..8b7cf589c1 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -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(), }; diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 38ba0d0cfe..805e2d7682 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -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 @@ -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, diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index df2278f53c..5ada50c0bb 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -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 ? (", " diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 7eb927f866..b1317a9103 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -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) {}); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index eb4e1fa1d3..4eff615c20 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1949,7 +1949,7 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) { AddComponents(HistoryMessageSuggestedPost::Bit()); } auto suggest = Get(); - 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()) { - 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(); - 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( + this, + _from, + Data::GiftType::Ton, + data.vamount().v); }, [&](const MTPDmessageActionPrizeStars &data) { _media = std::make_unique( this, diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 92714a2e2d..f934726c64 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -623,7 +623,7 @@ struct HistoryMessageFactcheck struct HistoryMessageSuggestedPost : RuntimeComponent { - int stars = 0; + CreditsAmount price; TimeId date = 0; mtpRequestId requestId = 0; bool accepted = false; @@ -701,7 +701,7 @@ struct HistoryServiceTodoAppendTasks struct HistoryServiceSuggestDecision : RuntimeComponent , HistoryServiceDependentData { - int stars = 0; + CreditsAmount price; TimeId date = 0; QString rejectComment; bool rejected = false; diff --git a/Telegram/SourceFiles/history/history_item_reply_markup.cpp b/Telegram/SourceFiles/history/history_item_reply_markup.cpp index 4a37ca15eb..8ca15fe623 100644 --- a/Telegram/SourceFiles/history/history_item_reply_markup.cpp +++ b/Telegram/SourceFiles/history/history_item_reply_markup.cpp @@ -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; } diff --git a/Telegram/SourceFiles/history/history_item_reply_markup.h b/Telegram/SourceFiles/history/history_item_reply_markup.h index be9084211e..03740b1ea6 100644 --- a/Telegram/SourceFiles/history/history_item_reply_markup.h +++ b/Telegram/SourceFiles/history/history_item_reply_markup.h @@ -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; diff --git a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp index f8b3b89f81..b5c8f84097 100644 --- a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp +++ b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp @@ -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)), diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp index 39679cb448..698e46bd19 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -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); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h index 86a30c094a..5b2c2d4bca 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h @@ -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; diff --git a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp index 9a81e9afa9..163278761e 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp @@ -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) diff --git a/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp b/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp index 300a067033..377cebf260 100644 --- a/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp +++ b/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp @@ -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 value, + rpl::producer 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()); diff --git a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.cpp b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.cpp index 26130b96f0..89dcda70a3 100644 --- a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.cpp +++ b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_common.cpp @@ -603,7 +603,7 @@ object_ptr 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( box, diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp index 70e54d9bb7..88c7744f73 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp @@ -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); diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h index 2f0b14848f..6750d05540 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h @@ -18,7 +18,7 @@ namespace Info::ChannelEarn { float64 rate, int afterFloat); [[nodiscard]] QString ToUsd( - StarsAmount value, + CreditsAmount value, float64 rate, int afterFloat); diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp index 3d28ab3025..bda1ca5495 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp @@ -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 currencyValue, - rpl::producer creditsValue, + rpl::producer creditsValue, const tr::phrase<> &text, bool showCurrency, bool showCredits) { @@ -741,8 +741,10 @@ void InnerWidget::fill() { const auto creditsLabel = Ui::CreateChild( 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( diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 31a9468dfb..ba4ac5c49e 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -940,19 +940,20 @@ rpl::producer AddCurrencyAction( return state->balance.value(); } -rpl::producer AddCreditsAction( +rpl::producer AddCreditsAction( not_null user, not_null wrap, not_null controller) { struct State final { - rpl::variable balance; + rpl::variable balance; }; const auto state = wrap->lifetime().make_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 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 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 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 user) { diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index 33a131d110..59a66d8732 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -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, diff --git a/Telegram/SourceFiles/lang/lang_tag.cpp b/Telegram/SourceFiles/lang/lang_tag.cpp index d11cb1039f..eb6f938bf8 100644 --- a/Telegram/SourceFiles/lang/lang_tag.cpp +++ b/Telegram/SourceFiles/lang/lang_tag.cpp @@ -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.); } diff --git a/Telegram/SourceFiles/lang/lang_tag.h b/Telegram/SourceFiles/lang/lang_tag.h index 1012d27714..40f3ef9972 100644 --- a/Telegram/SourceFiles/lang/lang_tag.h +++ b/Telegram/SourceFiles/lang/lang_tag.h @@ -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; diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 22fd24059c..54f9cd1816 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -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 = MessageAction; messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; messageActionTodoAppendTasks#c7edbc83 list:Vector = 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 users:Vector 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 = 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; -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; diff --git a/Telegram/SourceFiles/payments/payments_form.cpp b/Telegram/SourceFiles/payments/payments_form.cpp index a17b2dcfd4..20bebbef6e 100644 --- a/Telegram/SourceFiles/payments/payments_form.cpp +++ b/Telegram/SourceFiles/payments/payments_form.cpp @@ -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 }); diff --git a/Telegram/SourceFiles/payments/payments_form.h b/Telegram/SourceFiles/payments/payments_form.h index 2e199e3598..598f9a23d8 100644 --- a/Telegram/SourceFiles/payments/payments_form.h +++ b/Telegram/SourceFiles/payments/payments_form.h @@ -211,7 +211,7 @@ struct CreditsReceiptData { QString description; PhotoData *photo = nullptr; PeerId peerId = PeerId(0); - StarsAmount credits; + CreditsAmount credits; TimeId date = 0; }; diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp index 1786d250ce..e227c5933b 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp @@ -33,7 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Settings { [[nodiscard]] not_null AddBalanceWidget( not_null parent, - rpl::producer balanceValue, + rpl::producer balanceValue, bool rightAlign, rpl::producer opacityValue = nullptr); } // namespace Settings diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h index 1468d53baf..bada338249 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h @@ -41,7 +41,7 @@ struct PaidReactionBoxArgs { QString channel; Fn(rpl::producer amount)> submit; - rpl::producer balanceValue; + rpl::producer balanceValue; Fn send; }; diff --git a/Telegram/SourceFiles/settings/settings_credits.cpp b/Telegram/SourceFiles/settings/settings_credits.cpp index 9fd0ed483f..d71be42094 100644 --- a/Telegram/SourceFiles/settings/settings_credits.cpp +++ b/Telegram/SourceFiles/settings/settings_credits.cpp @@ -405,7 +405,7 @@ void Credits::setupContent() { const auto balanceAmount = Ui::CreateChild( 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 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()) { diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 0914fb1ad7..9acd7b6bb9 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -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 show, not_null container, not_null peer, - StarsAmount minimumCredits, + CreditsAmount minimumCredits, Fn paid, rpl::producer subtitle, std::vector 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 AddBalanceWidget( not_null parent, - rpl::producer balanceValue, + rpl::producer balanceValue, bool rightAlign, rpl::producer opacityValue) { struct State final { @@ -720,10 +720,10 @@ not_null 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 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( @@ -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(source) @@ -2507,7 +2507,7 @@ void AddWithdrawalWidget( not_null controller, not_null peer, rpl::producer secondButtonUrl, - rpl::producer availableBalanceValue, + rpl::producer availableBalanceValue, rpl::producer dateValue, bool withdrawalEnabled, rpl::producer 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; + using Balance = rpl::variable; const auto currentBalance = input->lifetime().make_state( 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); } diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index a1bf02a4bd..ceea526d12 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -72,14 +72,14 @@ void FillCreditOptions( std::shared_ptr show, not_null container, not_null peer, - StarsAmount minCredits, + CreditsAmount minCredits, Fn paid, rpl::producer subtitle, std::vector preloadedTopupOptions); [[nodiscard]] not_null AddBalanceWidget( not_null parent, - rpl::producer balanceValue, + rpl::producer balanceValue, bool rightAlign, rpl::producer opacityValue = nullptr); @@ -88,7 +88,7 @@ void AddWithdrawalWidget( not_null controller, not_null peer, rpl::producer secondButtonUrl, - rpl::producer availableBalanceValue, + rpl::producer availableBalanceValue, rpl::producer dateValue, bool withdrawalEnabled, rpl::producer usdValue); diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index 1d65911e3f..289eba499f 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -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), diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 977126555b..6647362881 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -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" diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index cbcb74e24e..e39e6ba018 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -136,6 +136,33 @@ auto EmptyMessageDraftSources() return cWorkingDir() + u"tdata/tdld/"_q; } +[[nodiscard]] std::pair 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 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 owner, const QString &dataName) @@ -1276,7 +1303,7 @@ void Account::writeDrafts(not_null 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) { 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) { QByteArray textTagsSerialized; qint64 keyValue = 0; qint64 messageIdPeer = 0, messageIdMsg = 0; - quint64 suggestSerialized = 0; + std::pair suggestSerialized; qint32 keyValueOld = 0; QString webpageUrl; qint32 webpageForceLargeMedia = 0; @@ -1572,7 +1599,9 @@ void Account::readDraftsWithCursors(not_null 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) { 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, diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp index d7822ee730..a3dcc9f066 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp @@ -164,11 +164,11 @@ not_null CreateSingleStarWidget( not_null AddInputFieldForCredits( not_null container, - rpl::producer value) { + rpl::producer value) { const auto &st = st::botEarnInputField; const auto inputContainer = container->add( CreateSkipWidget(container, st.heightMin)); - const auto currentValue = rpl::variable( + const auto currentValue = rpl::variable( rpl::duplicate(value)); const auto input = CreateChild( inputContainer, @@ -178,7 +178,7 @@ not_null 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()); diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.h b/Telegram/SourceFiles/ui/effects/credits_graphics.h index 022c7cac80..5df03f4af2 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.h +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.h @@ -44,7 +44,7 @@ using PaintRoundImageCallback = Fn AddInputFieldForCredits( not_null container, - rpl::producer value); + rpl::producer value); PaintRoundImageCallback GenerateCreditsPaintUserpicCallback( const Data::CreditsHistoryEntry &entry); diff --git a/Telegram/SourceFiles/ui/ui_pch.h b/Telegram/SourceFiles/ui/ui_pch.h index 10bd37c13e..eb9a86a713 100644 --- a/Telegram/SourceFiles/ui/ui_pch.h +++ b/Telegram/SourceFiles/ui/ui_pch.h @@ -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"