diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 42e5c7ba1..279a526a8 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -468,6 +468,7 @@ 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_credits.cpp b/Telegram/SourceFiles/api/api_credits.cpp index 175112c40..4429de7bf 100644 --- a/Telegram/SourceFiles/api/api_credits.cpp +++ b/Telegram/SourceFiles/api/api_credits.cpp @@ -74,7 +74,8 @@ constexpr auto kTransactionsLimit = 100; }).value; const auto stargift = tl.data().vstargift(); const auto reaction = tl.data().is_reaction(); - const auto incoming = (int64(tl.data().vstars().v) >= 0); + const auto amount = Data::FromTL(tl.data().vstars()); + const auto incoming = (amount >= StarsAmount()); const auto saveActorId = (reaction || !extended.empty()) && incoming; return Data::CreditsHistoryEntry{ .id = qs(tl.data().vid()), @@ -83,7 +84,7 @@ constexpr auto kTransactionsLimit = 100; .date = base::unixtime::parse(tl.data().vdate().v), .photoId = photo ? photo->id : 0, .extended = std::move(extended), - .credits = tl.data().vstars().v, + .credits = Data::FromTL(tl.data().vstars()), .bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()), .barePeerId = saveActorId ? peer->id.value : barePeerId, .bareGiveawayMsgId = uint64( @@ -181,7 +182,7 @@ constexpr auto kTransactionsLimit = 100; return Data::CreditsStatusSlice{ .list = std::move(entries), .subscriptions = std::move(subscriptions), - .balance = status.data().vbalance().v, + .balance = Data::FromTL(status.data().vbalance()), .subscriptionsMissingBalance = status.data().vsubscriptions_missing_balance().value_or_empty(), .allLoaded = !status.data().vnext_offset().has_value() @@ -268,8 +269,8 @@ void CreditsStatus::request( _peer->isSelf() ? MTP_inputPeerSelf() : _peer->input )).done([=](const TLResult &result) { _requestId = 0; - const auto balance = result.data().vbalance().v; - _peer->session().credits().apply(_peer->id, balance); + const auto &balance = result.data().vbalance(); + _peer->session().credits().apply(_peer->id, Data::FromTL(balance)); if (const auto onstack = done) { onstack(StatusFromTL(result, _peer)); } @@ -348,7 +349,9 @@ rpl::producer> PremiumPeerBot( const auto api = lifetime.make_state(&session->mtp()); api->request(MTPcontacts_ResolveUsername( - MTP_string(username) + MTP_flags(0), + MTP_string(username), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { session->data().processUsers(result.data().vusers()); session->data().processChats(result.data().vchats()); @@ -380,12 +383,13 @@ 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 = status.vcurrent_balance().v, - .availableBalance = status.vavailable_balance().v, - .overallRevenue = status.voverall_revenue().v, + .currentBalance = FromTL(status.vcurrent_balance()), + .availableBalance = FromTL(status.vavailable_balance()), + .overallRevenue = FromTL(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_single_message_search.cpp b/Telegram/SourceFiles/api/api_single_message_search.cpp index 0875091bc..2597c2f05 100644 --- a/Telegram/SourceFiles/api/api_single_message_search.cpp +++ b/Telegram/SourceFiles/api/api_single_message_search.cpp @@ -181,7 +181,9 @@ std::optional SingleMessageSearch::performLookupByUsername( ready(); }; _requestId = _session->api().request(MTPcontacts_ResolveUsername( - MTP_string(username) + MTP_flags(0), + MTP_string(username), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { result.match([&](const MTPDcontacts_resolvedPeer &data) { _session->data().processUsers(data.vusers()); diff --git a/Telegram/SourceFiles/boxes/gift_credits_box.cpp b/Telegram/SourceFiles/boxes/gift_credits_box.cpp index 896ecea51..2df2d9f99 100644 --- a/Telegram/SourceFiles/boxes/gift_credits_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_credits_box.cpp @@ -122,7 +122,7 @@ void GiftCreditsBox( Main::MakeSessionShow(box->uiShow(), &peer->session()), box->verticalLayout(), peer, - 0, + StarsAmount(), [=] { 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 542189659..1c0b80dee 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -255,8 +255,8 @@ object_ptr MakeStarGiftStarsValue( auto star = session->data().customEmojiManager().creditsEmoji(); const auto label = Ui::CreateChild( raw, - rpl::single( - star.append(' ' + Lang::FormatCountDecimal(entry.credits))), + rpl::single(star.append( + ' ' + Lang::FormatStarsAmountDecimal(entry.credits))), st::giveawayGiftCodeValue, st::defaultPopupMenu, std::move(makeContext)); @@ -1229,7 +1229,7 @@ void AddCreditsHistoryEntryTable( tr::lng_gift_link_label_gift(), tr::lng_gift_stars_title( lt_count, - rpl::single(float64(entry.credits)), + rpl::single(entry.credits.value()), Ui::Text::RichLangValue)); } { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 76fd9856b..dbfcead1a 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -1664,7 +1664,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::FormatCountDecimal(balance); + state->balance = Lang::FormatStarsAmountDecimal(balance); } const auto wrap = _controls.buttonsLayout->add( @@ -1689,7 +1689,7 @@ void Controller::fillBotCreditsButton() { if (data.balance) { wrap->toggle(true, anim::type::normal); } - state->balance = Lang::FormatCountDecimal(data.balance); + state->balance = Lang::FormatStarsAmountDecimal(data.balance); }); } { @@ -2227,7 +2227,9 @@ void Controller::saveHistoryVisibility() { void Controller::toggleBotManager(const QString &command) { const auto controller = _navigation->parentController(); _api.request(MTPcontacts_ResolveUsername( - MTP_string(kBotManagerUsername.utf16()) + MTP_flags(0), + MTP_string(kBotManagerUsername.utf16()), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { _peer->owner().processUsers(result.data().vusers()); _peer->owner().processChats(result.data().vchats()); diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 781e008d2..c05e29ed8 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -875,7 +875,7 @@ void SoldOutBox( Data::CreditsHistoryEntry{ .firstSaleDate = base::unixtime::parse(gift.info.firstSaleDate), .lastSaleDate = base::unixtime::parse(gift.info.lastSaleDate), - .credits = uint64(gift.info.stars), + .credits = StarsAmount(gift.info.stars), .bareGiftStickerId = gift.info.document->id, .peerType = Data::CreditsHistoryEntry::PeerType::Peer, .limitedCount = gift.info.limitedCount, diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 72865ea01..89c666188 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -899,7 +899,9 @@ void GifsListWidget::searchForGifs(const QString &query) { if (!_searchBot && !_searchBotRequestId) { const auto username = session().serverConfig().gifSearchUsername; _searchBotRequestId = _api.request(MTPcontacts_ResolveUsername( - MTP_string(username) + MTP_flags(0), + MTP_string(username), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { auto &data = result.data(); session().data().processUsers(data.vusers()); diff --git a/Telegram/SourceFiles/core/stars_amount.h b/Telegram/SourceFiles/core/stars_amount.h new file mode 100644 index 000000000..fc9c8df90 --- /dev/null +++ b/Telegram/SourceFiles/core/stars_amount.h @@ -0,0 +1,99 @@ +/* +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; + } + + 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; +} diff --git a/Telegram/SourceFiles/data/components/credits.cpp b/Telegram/SourceFiles/data/components/credits.cpp index e213fcf9a..cea4020d8 100644 --- a/Telegram/SourceFiles/data/components/credits.cpp +++ b/Telegram/SourceFiles/data/components/credits.cpp @@ -19,6 +19,11 @@ 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); }) { @@ -27,7 +32,7 @@ Credits::Credits(not_null session) Credits::~Credits() = default; void Credits::apply(const MTPDupdateStarsBalance &data) { - apply(data.vbalance().v); + apply(FromTL(data.vbalance())); } rpl::producer Credits::rateValue( @@ -65,13 +70,13 @@ rpl::producer Credits::loadedValue() const { ) | rpl::then(_loadedChanges.events() | rpl::map_to(true)); } -uint64 Credits::balance() const { +StarsAmount Credits::balance() const { return _nonLockedBalance.current(); } -uint64 Credits::balance(PeerId peerId) const { +StarsAmount Credits::balance(PeerId peerId) const { const auto it = _cachedPeerBalances.find(peerId); - return (it != _cachedPeerBalances.end()) ? it->second : 0; + return (it != _cachedPeerBalances.end()) ? it->second : StarsAmount(); } uint64 Credits::balanceCurrency(PeerId peerId) const { @@ -79,17 +84,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) : 0; + _nonLockedBalance = (_balance >= _locked) + ? (_balance - _locked) + : StarsAmount(); } -void Credits::lock(int count) { +void Credits::lock(StarsAmount count) { Expects(loaded()); - Expects(count >= 0); + Expects(count >= StarsAmount(0)); Expects(_locked + count <= _balance); _locked += count; @@ -97,8 +104,8 @@ void Credits::lock(int count) { updateNonLockedValue(); } -void Credits::unlock(int count) { - Expects(count >= 0); +void Credits::unlock(StarsAmount count) { + Expects(count >= StarsAmount(0)); Expects(_locked >= count); _locked -= count; @@ -106,12 +113,12 @@ void Credits::unlock(int count) { updateNonLockedValue(); } -void Credits::withdrawLocked(int count) { - Expects(count >= 0); +void Credits::withdrawLocked(StarsAmount count) { + Expects(count >= StarsAmount(0)); Expects(_locked >= count); _locked -= count; - apply(_balance >= count ? (_balance - count) : 0); + apply(_balance >= count ? (_balance - count) : StarsAmount(0)); invalidate(); } @@ -119,7 +126,7 @@ void Credits::invalidate() { _reload.call(); } -void Credits::apply(uint64 balance) { +void Credits::apply(StarsAmount balance) { _balance = balance; updateNonLockedValue(); @@ -129,7 +136,7 @@ void Credits::apply(uint64 balance) { } } -void Credits::apply(PeerId peerId, uint64 balance) { +void Credits::apply(PeerId peerId, StarsAmount balance) { _cachedPeerBalances[peerId] = balance; } diff --git a/Telegram/SourceFiles/data/components/credits.h b/Telegram/SourceFiles/data/components/credits.h index da953b29b..757e494ef 100644 --- a/Telegram/SourceFiles/data/components/credits.h +++ b/Telegram/SourceFiles/data/components/credits.h @@ -17,30 +17,32 @@ 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(uint64 balance); - void apply(PeerId peerId, uint64 balance); + void apply(StarsAmount balance); + void apply(PeerId peerId, StarsAmount balance); [[nodiscard]] bool loaded() const; [[nodiscard]] rpl::producer loadedValue() const; - [[nodiscard]] uint64 balance() const; - [[nodiscard]] uint64 balance(PeerId peerId) const; - [[nodiscard]] rpl::producer balanceValue() const; + [[nodiscard]] StarsAmount balance() const; + [[nodiscard]] StarsAmount balance(PeerId peerId) const; + [[nodiscard]] rpl::producer balanceValue() const; [[nodiscard]] rpl::producer rateValue( not_null ownedBotOrChannel); void applyCurrency(PeerId peerId, uint64 balance); [[nodiscard]] uint64 balanceCurrency(PeerId peerId) const; - void lock(int count); - void unlock(int count); - void withdrawLocked(int count); + void lock(StarsAmount count); + void unlock(StarsAmount count); + void withdrawLocked(StarsAmount count); void invalidate(); void apply(const MTPDupdateStarsBalance &data); @@ -52,12 +54,12 @@ private: std::unique_ptr _loader; - base::flat_map _cachedPeerBalances; + base::flat_map _cachedPeerBalances; base::flat_map _cachedPeerCurrencyBalances; - uint64 _balance = 0; - uint64 _locked = 0; - rpl::variable _nonLockedBalance; + StarsAmount _balance; + StarsAmount _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 fe77aedc5..1efc07d2b 100644 --- a/Telegram/SourceFiles/data/data_credits.h +++ b/Telegram/SourceFiles/data/data_credits.h @@ -57,7 +57,7 @@ struct CreditsHistoryEntry final { QDateTime lastSaleDate; PhotoId photoId = 0; std::vector extended; - uint64 credits = 0; + StarsAmount credits; uint64 bareMsgId = 0; uint64 barePeerId = 0; uint64 bareGiveawayMsgId = 0; @@ -89,7 +89,7 @@ struct CreditsStatusSlice final { using OffsetToken = QString; std::vector list; std::vector subscriptions; - uint64 balance = 0; + StarsAmount 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 c82d58a74..dd5a2307a 100644 --- a/Telegram/SourceFiles/data/data_credits_earn.h +++ b/Telegram/SourceFiles/data/data_credits_earn.h @@ -13,16 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { -using CreditsEarnInt = uint64; - struct CreditsEarnStatistics final { explicit operator bool() const { return !!usdRate; } Data::StatisticalGraph revenueGraph; - CreditsEarnInt currentBalance = 0; - CreditsEarnInt availableBalance = 0; - CreditsEarnInt overallRevenue = 0; + StarsAmount currentBalance; + StarsAmount availableBalance; + StarsAmount overallRevenue; float64 usdRate = 0.; bool isWithdrawalEnabled = false; QDateTime nextWithdrawalAt; diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 57bb4cbf2..a3e581a2d 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -2220,7 +2220,7 @@ void MessageReactions::scheduleSendPaid( _paid->scheduledPrivacySet = anonymous.has_value(); } if (count > 0) { - _item->history()->session().credits().lock(count); + _item->history()->session().credits().lock(StarsAmount(count)); } _item->history()->owner().reactions().schedulePaid(_item); } @@ -2233,7 +2233,8 @@ void MessageReactions::cancelScheduledPaid() { if (_paid) { if (_paid->scheduledFlag) { if (const auto amount = int(_paid->scheduled)) { - _item->history()->session().credits().unlock(amount); + _item->history()->session().credits().unlock( + StarsAmount(amount)); } _paid->scheduled = 0; _paid->scheduledFlag = 0; @@ -2296,9 +2297,9 @@ void MessageReactions::finishPaidSending( if (const auto amount = send.count) { const auto credits = &_item->history()->session().credits(); if (success) { - credits->withdrawLocked(amount); + credits->withdrawLocked(StarsAmount(amount)); } else { - credits->unlock(amount); + credits->unlock(StarsAmount(amount)); } } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b8f8fb0fa..ddd81cf80 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1561,7 +1561,10 @@ void HistoryWidget::updateInlineBotQuery() { _inlineLookingUpBot = true; const auto username = _inlineBotUsername; _inlineBotResolveRequestId = _api.request( - MTPcontacts_ResolveUsername(MTP_string(username)) + MTPcontacts_ResolveUsername( + MTP_flags(0), + MTP_string(username), + MTP_string()) ).done([=](const MTPcontacts_ResolvedPeer &result) { const auto &data = result.data(); const auto resolvedBot = [&]() -> UserData* { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 0196405c9..c63696f8a 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -3265,7 +3265,10 @@ void ComposeControls::updateInlineBotQuery() { _inlineLookingUpBot = true; const auto username = _inlineBotUsername; _inlineBotResolveRequestId = api.request( - MTPcontacts_ResolveUsername(MTP_string(username)) + MTPcontacts_ResolveUsername( + MTP_flags(0), + MTP_string(username), + MTP_string()) ).done([=](const MTPcontacts_ResolvedPeer &result) { Expects(result.type() == mtpc_contacts_resolvedPeer); 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 b96427bca..2cea711b1 100644 --- a/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp +++ b/Telegram/SourceFiles/info/bot/earn/info_bot_earn_list.cpp @@ -125,7 +125,9 @@ void InnerWidget::fill() { return _state.availableBalance; }) ); - auto valueToString = [](uint64 v) { return Lang::FormatCountDecimal(v); }; + auto valueToString = [](StarsAmount v) { + return Lang::FormatStarsAmountDecimal(v); + }; if (data.revenueGraph.chart) { Ui::AddSkip(container); @@ -149,7 +151,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), @@ -165,7 +167,7 @@ void InnerWidget::fill() { line, std::move( value - ) | rpl::map([=](uint64 v) { + ) | rpl::map([=](StarsAmount v) { return v ? ToUsd(v, multiplier, kMinorLength) : QString(); }), st::channelEarnOverviewSubMinorLabel); @@ -242,7 +244,9 @@ void InnerWidget::fill() { rpl::duplicate(dateValue) | rpl::map([=](const QDateTime &dt) { return !dt.isNull() || (!_state.isWithdrawalEnabled); }), - rpl::duplicate(availableBalanceValue) | rpl::map([=](uint64 v) { + rpl::duplicate( + availableBalanceValue + ) | rpl::map([=](StarsAmount v) { return v ? ToUsd(v, multiplier, kMinorLength) : QString(); })); } diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp index 11f17b8b3..70e54d9bb 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp @@ -50,12 +50,16 @@ QString ToUsd( Data::EarnInt value, float64 rate, int afterFloat) { + return ToUsd(StarsAmount(value), rate, afterFloat); +} + +QString ToUsd( + StarsAmount value, + float64 rate, + int afterFloat) { constexpr auto kApproximately = QChar(0x2248); - const auto result = value - / float64(Data::kEarnMultiplier) - * rate - * Data::kEarnMultiplier; + const auto result = int64(base::SafeRound(value.value() * rate)); return QString(kApproximately) + QChar('$') + MajorPart(result) diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h index 7fcd19b4d..2f0b14848 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.h @@ -17,5 +17,9 @@ namespace Info::ChannelEarn { Data::EarnInt value, float64 rate, int afterFloat); +[[nodiscard]] QString ToUsd( + StarsAmount value, + float64 rate, + int afterFloat); } // namespace Info::ChannelEarn 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 08687b9c0..ea6b64c32 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 @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_color_box.h" // AddLevelBadge. #include "chat_helpers/stickers_emoji_pack.h" #include "core/application.h" +#include "data/components/credits.h" #include "data/data_channel.h" #include "data/data_premium_limits.h" #include "data/data_session.h" @@ -252,10 +253,9 @@ void InnerWidget::load() { } const auto &data = d.vstatus().data(); auto &e = _state.creditsEarn; - e.currentBalance = data.vcurrent_balance().v; - e.availableBalance = data.vavailable_balance().v; - e.overallRevenue = data.voverall_revenue().v; - e.overallRevenue = data.voverall_revenue().v; + e.currentBalance = Data::FromTL(data.vcurrent_balance()); + e.availableBalance = Data::FromTL(data.vavailable_balance()); + e.overallRevenue = Data::FromTL(data.voverall_revenue()); e.isWithdrawalEnabled = data.is_withdrawal_enabled(); e.nextWithdrawalAt = data.vnext_withdrawal_at() ? base::unixtime::parse( @@ -359,7 +359,7 @@ void InnerWidget::fill() { //constexpr auto kApproximately = QChar(0x2248); const auto multiplier = data.usdRate; - const auto creditsToUsdMap = [=](EarnInt c) { + const auto creditsToUsdMap = [=](StarsAmount c) { const auto creditsMultiplier = _state.creditsEarn.usdRate * Data::kEarnMultiplier; return c ? ToUsd(c, creditsMultiplier, 0) : QString(); @@ -679,7 +679,7 @@ void InnerWidget::fill() { const auto addOverview = [&]( rpl::producer currencyValue, - rpl::producer creditsValue, + rpl::producer creditsValue, const tr::phrase<> &text, bool showCurrency, bool showCredits) { @@ -713,8 +713,8 @@ void InnerWidget::fill() { const auto creditsLabel = Ui::CreateChild( line, - rpl::duplicate(creditsValue) | rpl::map([](EarnInt value) { - return QString::number(value); + rpl::duplicate(creditsValue) | rpl::map([](StarsAmount value) { + return Lang::FormatStarsAmountDecimal(value); }), st::channelEarnOverviewMajorLabel); const auto icon = Ui::CreateSingleStarWidget( @@ -733,7 +733,7 @@ void InnerWidget::fill() { int available, const QSize &size, const QSize &creditsSize, - EarnInt credits) { + StarsAmount credits) { const auto skip = st::channelEarnOverviewSubMinorLabelPos.x(); line->resize(line->width(), size.height()); minorLabel->moveToLeft( @@ -922,7 +922,7 @@ void InnerWidget::fill() { : tr::lng_channel_earn_balance_about_temp); Ui::AddSkip(container); } - if (creditsData.availableBalance > 0) { + if (creditsData.availableBalance.value() > 0) { AddHeader(container, tr::lng_bot_earn_balance_title); auto availableBalanceValue = rpl::single( creditsData.availableBalance diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 7ade4a32e..43b4ff317 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -866,19 +866,19 @@ 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 > 0), + state->balance.value() | rpl::map(rpl::mappers::_1 > StarsAmount(0)), [=] { parentController->showSection(Info::BotEarn::Make(user)); }, nullptr); { @@ -918,7 +918,7 @@ rpl::producer AddCreditsAction( ) | rpl::start_with_next([=, &st]( int width, const QString &button, - uint64 balance) { + StarsAmount balance) { const auto available = width - rect::m::sum::h(st.padding) - st.style.font->width(button) @@ -926,7 +926,7 @@ rpl::producer AddCreditsAction( name->setMarkedText( base::duplicate(icon) .append(QChar(' ')) - .append(Lang::FormatCountDecimal(balance)), + .append(Lang::FormatStarsAmountDecimal(balance)), Core::MarkedTextContext{ .session = &user->session(), .customEmojiRepaint = [=] { name->update(); }, @@ -2130,7 +2130,8 @@ void ActionsFiller::addBalanceActions(not_null user) { rpl::combine( std::move(currencyBalance), std::move(creditsBalance) - ) | rpl::map((rpl::mappers::_1 + rpl::mappers::_2) > 0)); + ) | rpl::map((rpl::mappers::_1 > 0) + || (rpl::mappers::_2 > StarsAmount(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 3dbe08b96..799416844 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -916,8 +916,7 @@ void CreditsRow::init() { st::semiboldTextStyle, TextWithEntities() .append(_entry.in ? QChar('+') : kMinus) - .append( - Lang::FormatCountDecimal(std::abs(int64(_entry.credits)))) + .append(Lang::FormatStarsAmountDecimal(_entry.credits.abs())) .append(QChar(' ')) .append(manager.creditsEmoji()), kMarkupTextOptions, diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 7481a0bf5..a23d3b53f 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -2346,7 +2346,9 @@ void AttachWebView::resolveUsername( } _session->api().request(base::take(_requestId)).cancel(); _requestId = _session->api().request(MTPcontacts_ResolveUsername( - MTP_string(_botUsername) + MTP_flags(0), + MTP_string(_botUsername), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { _requestId = 0; result.match([&](const MTPDcontacts_resolvedPeer &data) { diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp index 8078828d6..b4fbc4e84 100644 --- a/Telegram/SourceFiles/iv/iv_instance.cpp +++ b/Telegram/SourceFiles/iv/iv_instance.cpp @@ -241,7 +241,9 @@ void Shown::fillChannelJoinedValues(const Prepared &result) { const auto channel = _session->data().channel(channelId); if (!channel->isLoaded() && !channel->username().isEmpty()) { channel->session().api().request(MTPcontacts_ResolveUsername( - MTP_string(channel->username()) + MTP_flags(0), + MTP_string(channel->username()), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { channel->owner().processUsers(result.data().vusers()); channel->owner().processChats(result.data().vchats()); diff --git a/Telegram/SourceFiles/lang/lang_tag.cpp b/Telegram/SourceFiles/lang/lang_tag.cpp index 2435a77eb..32662ad0a 100644 --- a/Telegram/SourceFiles/lang/lang_tag.cpp +++ b/Telegram/SourceFiles/lang/lang_tag.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "lang/lang_tag.h" +#include "core/stars_amount.h" #include "lang/lang_keys.h" #include "ui/text/text.h" #include "base/qt/qt_common_adapters.h" @@ -945,6 +946,21 @@ QString FormatCountDecimal(int64 number) { return QString("%L1").arg(number); } +QString FormatExactCountDecimal(float64 number) { + return QString("%L1").arg(number); +} + +ShortenedCount FormatStarsAmountToShort(StarsAmount amount) { + const auto attempt = FormatCountToShort(amount.whole()); + return attempt.shortened ? attempt : ShortenedCount{ + .string = FormatStarsAmountDecimal(amount), + }; +} + +QString FormatStarsAmountDecimal(StarsAmount amount) { + return FormatExactCountDecimal(amount.value()); +} + PluralResult Plural( ushort keyBase, float64 value, diff --git a/Telegram/SourceFiles/lang/lang_tag.h b/Telegram/SourceFiles/lang/lang_tag.h index b1163b06e..cd99cbd82 100644 --- a/Telegram/SourceFiles/lang/lang_tag.h +++ b/Telegram/SourceFiles/lang/lang_tag.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +class StarsAmount; + enum lngtag_count : int; namespace Lang { @@ -26,6 +28,9 @@ 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); struct PluralResult { int keyShift = 0; diff --git a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp index 850d5c6c1..72e69e48a 100644 --- a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp +++ b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp @@ -416,10 +416,11 @@ void ResolveChannel( ).arg(QString::number(error.code()) + ':' + error.type())); fail(); }; - mtp->send( - MTPcontacts_ResolveUsername(MTP_string(username)), - doneHandler, - failHandler); + mtp->send(MTPcontacts_ResolveUsername( + MTP_flags(0), + MTP_string(username), + MTP_string() + ), doneHandler, failHandler); } std::optional GetMessagesElement( diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index db18d216e..c6b4a89af 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -151,8 +151,8 @@ messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageActi messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#8f31b327 flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; -messageActionPaymentSent#96163f56 flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string = MessageAction; +messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; +messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; @@ -235,7 +235,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#1f58e369 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int = UserFull; +userFull#979d2376 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram = UserFull; contact#145ade0b user_id:long mutual:Bool = Contact; @@ -421,12 +421,11 @@ updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Messag updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueBalances = Update; -updateStarsBalance#fb85198 balance:long = Update; +updateStarsBalance#4e80a379 balance:StarsAmount = Update; updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; updatePaidReactionPrivacy#51ca7aec private:Bool = Update; -updateBotSubscriptionExpire#2d13c6ee user_id:long payload:string invoice_slug:string until_date:int qts:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1832,9 +1831,9 @@ starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#35d4f276 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int = StarsTransaction; +starsTransaction#64dfc926 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount = StarsTransaction; -payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; +payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; @@ -1842,7 +1841,7 @@ stories.foundStories#e2de7737 flags:# count:int stories:Vector next_ geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; -starsRevenueStatus#79342946 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long next_withdrawal_at:flags.1?int = StarsRevenueStatus; +starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; payments.starsRevenueStats#c92bb73b revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; @@ -1891,6 +1890,19 @@ messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult pee botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; +starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; + +connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; + +payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; + +payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; + +starsAmount#bbb6b4a3 amount:long nanos:int = 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; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2056,7 +2068,7 @@ contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; +contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; @@ -2296,6 +2308,7 @@ messages.reportSponsoredMessage#1af3dbb8 peer:InputPeer random_id:bytes option:b messages.getSponsoredMessages#9bd2f439 peer:InputPeer = messages.SponsoredMessages; messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; +messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2430,6 +2443,8 @@ bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; +bots.getAdminedBots#b0711d83 = Vector; +bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; @@ -2465,7 +2480,12 @@ payments.getStarGifts#c4563590 hash:int = payments.StarGifts; payments.getUserStarGifts#5e72c7e1 user_id:InputUser offset:string limit:int = payments.UserStarGifts; payments.saveStarGift#87acf08e flags:# unsave:flags.0?true user_id:InputUser msg_id:int = Bool; payments.convertStarGift#421e027 user_id:InputUser msg_id:int = Bool; -payments.botCancelStarsSubscription#57f9ece6 flags:# restore:flags.0?true user_id:InputUser invoice_slug:flags.1?string charge_id:flags.2?string = Bool; +payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; +payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; +payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; +payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; +payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; +payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; @@ -2585,4 +2605,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; -// LAYER 193 +// LAYER 195 diff --git a/Telegram/SourceFiles/payments/payments_form.cpp b/Telegram/SourceFiles/payments/payments_form.cpp index 382226840..6431796e0 100644 --- a/Telegram/SourceFiles/payments/payments_form.cpp +++ b/Telegram/SourceFiles/payments/payments_form.cpp @@ -611,7 +611,7 @@ void Form::processReceipt(const MTPDpayments_paymentReceiptStars &data) { ImageLocation()) : nullptr, .peerId = peerFromUser(data.vbot_id().v), - .credits = data.vtotal_amount().v, + .credits = StarsAmount(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 d93fce51f..a2106cb53 100644 --- a/Telegram/SourceFiles/payments/payments_form.h +++ b/Telegram/SourceFiles/payments/payments_form.h @@ -210,7 +210,7 @@ struct CreditsReceiptData { QString description; PhotoData *photo = nullptr; PeerId peerId = PeerId(0); - uint64 credits = 0; + StarsAmount 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 77342222e..399b18e19 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp @@ -29,7 +29,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 8cd21f1cf..61a2b084b 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.h +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.h @@ -36,7 +36,7 @@ struct PaidReactionBoxArgs { QString channel; Fn(rpl::producer amount)> submit; - rpl::producer balanceValue; + rpl::producer balanceValue; Fn send; }; diff --git a/Telegram/SourceFiles/settings/business/settings_chatbots.cpp b/Telegram/SourceFiles/settings/business/settings_chatbots.cpp index c5006bf78..e85df4a99 100644 --- a/Telegram/SourceFiles/settings/business/settings_chatbots.cpp +++ b/Telegram/SourceFiles/settings/business/settings_chatbots.cpp @@ -272,7 +272,9 @@ Main::Session &PreviewController::session() const { const auto requestId = result.make_state(); *requestId = session->api().request(MTPcontacts_ResolveUsername( - MTP_string(extracted) + MTP_flags(0), + MTP_string(extracted), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { const auto &data = result.data(); session->data().processUsers(data.vusers()); diff --git a/Telegram/SourceFiles/settings/settings_credits.cpp b/Telegram/SourceFiles/settings/settings_credits.cpp index a407e7ad1..4927b572b 100644 --- a/Telegram/SourceFiles/settings/settings_credits.cpp +++ b/Telegram/SourceFiles/settings/settings_credits.cpp @@ -380,7 +380,7 @@ void Credits::setupContent() { const auto balanceAmount = Ui::CreateChild( balanceLine, _controller->session().credits().balanceValue( - ) | rpl::map(Lang::FormatCountDecimal), + ) | rpl::map(Lang::FormatStarsAmountDecimal), st::creditsSettingsBigBalance); balanceAmount->sizeValue() | rpl::start_with_next([=] { balanceLine->resize( @@ -430,7 +430,8 @@ void Credits::setupContent() { const auto options = state->api ? state->api->options() : Data::CreditTopupOptions(); - FillCreditOptions(show, inner, self, 0, paid, nullptr, options); + const auto amount = StarsAmount(); + FillCreditOptions(show, inner, self, amount, paid, nullptr, options); const auto button = box->addButton(tr::lng_close(), [=] { box->closeBox(); diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 889b7a921..54ddf8220 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -129,13 +129,13 @@ class Balance final public: using Ui::RpWidget::RpWidget; - void setBalance(uint64 balance) { + void setBalance(StarsAmount balance) { _balance = balance; - _tooltip = Lang::FormatCountDecimal(balance); + _tooltip = Lang::FormatStarsAmountDecimal(balance); } void enterEventHook(QEnterEvent *e) override { - if (_balance >= 10'000) { + if (_balance >= StarsAmount(10'000)) { Ui::Tooltip::Show(1000, this); } } @@ -158,7 +158,7 @@ public: private: QString _tooltip; - uint64 _balance = 0; + StarsAmount _balance; }; @@ -305,7 +305,7 @@ void AddViewMediaHandler( state->item->overrideMedia(std::make_unique( state->item, Data::Invoice{ - .amount = uint64(std::abs(int64(e.credits))), + .amount = uint64(e.credits.abs().whole()), .currency = Ui::kCreditsCurrency, .extendedMedia = std::move(fake), .isPaidMedia = true, @@ -429,7 +429,7 @@ void FillCreditOptions( std::shared_ptr show, not_null container, not_null peer, - int minimumCredits, + StarsAmount minimumCredits, Fn paid, rpl::producer subtitle, std::vector preloadedTopupOptions) { @@ -475,12 +475,12 @@ void FillCreditOptions( - int(singleStarWidth * 1.5); const auto buttonHeight = st.height + rect::m::sum::v(st.padding); const auto minCredits = (!options.empty() - && (minimumCredits > options.back().credits)) - ? 0 + && (minimumCredits > StarsAmount(options.back().credits))) + ? StarsAmount() : minimumCredits; for (auto i = 0; i < options.size(); i++) { const auto &option = options[i]; - if (option.credits < minCredits) { + if (StarsAmount(option.credits) < minCredits) { continue; } const auto button = [&] { @@ -607,7 +607,7 @@ void FillCreditOptions( not_null AddBalanceWidget( not_null parent, - rpl::producer balanceValue, + rpl::producer balanceValue, bool rightAlign, rpl::producer opacityValue) { struct State final { @@ -641,10 +641,12 @@ not_null AddBalanceWidget( + diffBetweenStarAndCount), state->label.style()->font->height + starSize.height()); }; - std::move(balanceValue) | rpl::start_with_next([=](uint64 value) { + std::move( + balanceValue + ) | rpl::start_with_next([=](StarsAmount value) { state->count.setText( st::semiboldTextStyle, - Lang::FormatCountToShort(value).string); + Lang::FormatStarsAmountToShort(value).string); balance->setBalance(value); resize(); }, balance->lifetime()); @@ -929,7 +931,7 @@ void ReceiptCreditsBox( auto &packs = session->giftBoxStickersPacks(); const auto document = starGiftSticker ? starGiftSticker - : packs.lookup(packs.monthsForStars(e.credits)); + : packs.lookup(packs.monthsForStars(e.credits.whole())); if (document && document->sticker()) { state->sticker = document; state->media = document->createMediaView(); @@ -1075,7 +1077,7 @@ void ReceiptCreditsBox( : (e.gift && !creditsHistoryStarGift) ? QString() : QString(kMinus)) - .append(Lang::FormatCountDecimal(std::abs(int64(e.credits)))) + .append(Lang::FormatStarsAmountDecimal(e.credits.abs())) .append(QChar(' ')) .append(session->data().customEmojiManager().creditsEmoji()); text->setMarkedText( @@ -1532,7 +1534,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 = uint64(count), + .credits = StarsAmount(count), .bareMsgId = uint64(), .barePeerId = (anonymous ? uint64() : peer->id.value), .peerType = (anonymous ? PeerType::Fragment : PeerType::Peer), @@ -1555,7 +1557,7 @@ void CreditsPrizeBox( .title = QString(), .description = TextWithEntities(), .date = base::unixtime::parse(date), - .credits = uint64(data.count), + .credits = StarsAmount(data.count), .barePeerId = data.channel ? data.channel->id.value : 0, @@ -1576,7 +1578,7 @@ void UserStarGiftBox( Data::CreditsHistoryEntry{ .description = data.message, .date = base::unixtime::parse(data.date), - .credits = uint64(data.info.stars), + .credits = StarsAmount(data.info.stars), .bareMsgId = uint64(data.messageId.bare), .barePeerId = data.fromId.value, .bareGiftStickerId = data.info.document->id, @@ -1607,7 +1609,7 @@ void StarGiftViewBox( .id = data.slug, .description = data.message, .date = base::unixtime::parse(item->date()), - .credits = uint64(data.count), + .credits = StarsAmount(data.count), .bareMsgId = uint64(item->id.bare), .barePeerId = item->history()->peer->id.value, .bareGiftStickerId = data.document ? data.document->id : 0, @@ -1640,7 +1642,7 @@ void ShowRefundInfoBox( auto info = Data::CreditsHistoryEntry(); info.id = refund->transactionId; info.date = base::unixtime::parse(item->date()); - info.credits = refund->amount; + info.credits = StarsAmount(refund->amount); info.barePeerId = refund->peer->id.value; info.peerType = Data::CreditsHistoryEntry::PeerType::Peer; info.refunded = true; @@ -1733,11 +1735,13 @@ object_ptr SubscriptionUserpic( void SmallBalanceBox( not_null box, std::shared_ptr show, - uint64 credits, + uint64 wholeCredits, SmallBalanceSource source, Fn paid) { Expects(show->session().credits().loaded()); + auto credits = StarsAmount(wholeCredits); + box->setWidth(st::boxWideWidth); box->addButton(tr::lng_close(), [=] { box->closeBox(); }); const auto done = [=] { @@ -1761,8 +1765,8 @@ void SmallBalanceBox( }); auto needed = show->session().credits().balanceValue( - ) | rpl::map([=](uint64 balance) { - return (balance < credits) ? (credits - balance) : 0; + ) | rpl::map([=](StarsAmount balance) { + return (balance < credits) ? (credits - balance) : StarsAmount(); }); const auto content = [&]() -> Ui::Premium::TopBarAbstract* { return box->setPinnedToTopContent(object_ptr( @@ -1773,7 +1777,11 @@ void SmallBalanceBox( lt_count, rpl::duplicate( needed - ) | rpl::filter(rpl::mappers::_1 > 0) | tr::to_count()), + ) | rpl::filter( + rpl::mappers::_1 > StarsAmount(0) + ) | rpl::map([](StarsAmount amount) { + return amount.value(); + })), .about = (v::is(source) ? tr::lng_credits_small_balance_subscribe( lt_channel, @@ -1857,7 +1865,7 @@ void AddWithdrawalWidget( not_null controller, not_null peer, rpl::producer secondButtonUrl, - rpl::producer availableBalanceValue, + rpl::producer availableBalanceValue, rpl::producer dateValue, rpl::producer lockedValue, rpl::producer usdValue) { @@ -1870,8 +1878,10 @@ void AddWithdrawalWidget( const auto majorLabel = Ui::CreateChild( labels, - rpl::duplicate(availableBalanceValue) | rpl::map([](uint64 v) { - return Lang::FormatCountDecimal(v); + rpl::duplicate( + availableBalanceValue + ) | rpl::map([](StarsAmount v) { + return Lang::FormatStarsAmountDecimal(v); }), st::channelEarnBalanceMajorLabel); const auto icon = Ui::CreateSingleStarWidget( @@ -1965,12 +1975,12 @@ void AddWithdrawalWidget( .session = session, .customEmojiRepaint = [=] { label->update(); }, }; - using Balance = rpl::variable; + using Balance = rpl::variable; const auto currentBalance = input->lifetime().make_state( rpl::duplicate(availableBalanceValue)); const auto process = [=] { const auto amount = input->getLastText().toDouble(); - if (amount >= currentBalance->current()) { + if (amount >= currentBalance->current().value()) { label->setText( tr::lng_bot_earn_balance_button_all(tr::now)); } else { @@ -2179,7 +2189,7 @@ void MaybeRequestBalanceIncrease( state->lifetime.destroy(); const auto balance = session->credits().balance(); - if (credits <= balance) { + if (StarsAmount(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 608f22cf0..0de7cb925 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -58,14 +58,14 @@ void FillCreditOptions( std::shared_ptr show, not_null container, not_null peer, - int minCredits, + StarsAmount 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); @@ -74,7 +74,7 @@ void AddWithdrawalWidget( not_null controller, not_null peer, rpl::producer secondButtonUrl, - rpl::producer availableBalanceValue, + rpl::producer availableBalanceValue, rpl::producer dateValue, rpl::producer lockedValue, rpl::producer usdValue); @@ -162,7 +162,7 @@ struct SmallBalanceSource : std::variant< void SmallBalanceBox( not_null box, std::shared_ptr show, - uint64 credits, + uint64 wholeCredits, SmallBalanceSource source, Fn paid); diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index 47aafcdaa..f1512531c 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -515,8 +515,10 @@ void SetupPremium( container, tr::lng_settings_credits(), controller->session().credits().balanceValue( - ) | rpl::map([=](uint64 c) { - return c ? Lang::FormatCountToShort(c).string : QString{}; + ) | rpl::map([=](StarsAmount c) { + return c + ? Lang::FormatStarsAmountToShort(c).string + : QString(); }), st::settingsButton), true diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 92db569f1..44569ddc5 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -133,6 +133,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/utils.h" #include "logs.h" #include "config.h" diff --git a/Telegram/SourceFiles/ui/controls/location_picker.cpp b/Telegram/SourceFiles/ui/controls/location_picker.cpp index 71b3c6f42..ca0d3ffd7 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.cpp +++ b/Telegram/SourceFiles/ui/controls/location_picker.cpp @@ -1155,7 +1155,9 @@ void LocationPicker::venuesRequest( } const auto username = _session->serverConfig().venueSearchUsername; _venuesBotRequestId = _api.request(MTPcontacts_ResolveUsername( - MTP_string(username) + MTP_flags(0), + MTP_string(username), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { auto &data = result.data(); _session->data().processUsers(data.vusers()); diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp index d79741299..97cf203c8 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp @@ -162,23 +162,23 @@ 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, st, tr::lng_bot_earn_out_ph(), - QString::number(currentValue.current()), - currentValue.current()); + QString::number(currentValue.current().whole()), + currentValue.current().whole()); rpl::duplicate( value - ) | rpl::start_with_next([=](uint64 v) { - input->changeLimit(v); - input->setText(QString::number(v)); + ) | rpl::start_with_next([=](StarsAmount v) { + input->changeLimit(v.whole()); + input->setText(QString::number(v.whole())); }, input->lifetime()); const auto icon = CreateSingleStarWidget( inputContainer, diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.h b/Telegram/SourceFiles/ui/effects/credits_graphics.h index d2a6ef7b8..a304a9ff5 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.h +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.h @@ -40,7 +40,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 4536e6650..10bd37c13 100644 --- a/Telegram/SourceFiles/ui/ui_pch.h +++ b/Telegram/SourceFiles/ui/ui_pch.h @@ -34,6 +34,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/flat_map.h" #include "base/flat_set.h" +#include "core/stars_amount.h" + #include "ui/arc_angles.h" #include "ui/text/text.h" #include "ui/effects/animations.h" diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 31e59520f..e2f6c51c3 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -461,7 +461,9 @@ void SessionNavigation::resolveUsername( } _api.request(base::take(_resolveRequestId)).cancel(); _resolveRequestId = _api.request(MTPcontacts_ResolveUsername( - MTP_string(username) + MTP_flags(0), + MTP_string(username), + MTP_string() )).done([=](const MTPcontacts_ResolvedPeer &result) { resolveDone(result, done); }).fail([=](const MTP::Error &error) {