diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 1a6827043b..6e4608a47d 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -458,7 +458,7 @@ auto GenerateGiftMedia( .sticker = sticker, .size = st::chatIntroStickerSize, .cacheTag = Tag::ChatIntroHelloSticker, - .singleTimePlayback = v::is(descriptor), + .stopOnLastFrame = v::is(descriptor), }; }; push(std::make_unique( diff --git a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp index fc0bf07cbb..9d9f0fd8ae 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp @@ -16,14 +16,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Stickers { GiftBoxPack::GiftBoxPack(not_null session) -: _session(session) -, _localMonths({ 1, 3, 6, 12, 24 }) { +: _session(session) { + _premium.dividers = { 1, 3, 6, 12, 24 }; + _ton.dividers = { 0, 10, 50 }; } GiftBoxPack::~GiftBoxPack() = default; rpl::producer<> GiftBoxPack::updated() const { - return _updated.events(); + return _premium.updated.events(); +} + +rpl::producer<> GiftBoxPack::tonUpdated() const { + return _ton.updated.events(); } int GiftBoxPack::monthsForStars(int stars) const { @@ -36,115 +41,113 @@ int GiftBoxPack::monthsForStars(int stars) const { } } -DocumentData *GiftBoxPack::lookup(int months, Type type) const { - const auto it = _setsData.find(type); - if (it == _setsData.end() || it->second.documents.empty()) { - return nullptr; - } +DocumentData *GiftBoxPack::lookup(int months) const { + return lookup(_premium, months, false); +} - const auto& documents = it->second.documents; - const auto itMonths = ranges::lower_bound(_localMonths, months); - const auto fallback = documents[0]; +DocumentData *GiftBoxPack::tonLookup(int amount) const { + return lookup(_ton, amount, true); +} - if (itMonths == begin(_localMonths)) { +DocumentData *GiftBoxPack::lookup( + const Pack &pack, + int divider, + bool exact) const { + const auto it = ranges::lower_bound(pack.dividers, divider); + const auto fallback = pack.documents.empty() + ? nullptr + : pack.documents.front(); + if (it == begin(pack.dividers)) { return fallback; - } else if (itMonths == end(_localMonths)) { - return documents.back(); + } else if (it == end(pack.dividers)) { + return pack.documents.back(); } - - const auto left = *(itMonths - 1); - const auto right = *itMonths; - const auto shift = (std::abs(months - left) < std::abs(months - right)) + const auto shift = exact + ? ((*it > divider) ? 1 : 0) + : (std::abs(divider - (*(it - 1))) < std::abs(divider - (*it))) ? -1 : 0; - const auto index = int( - std::distance(begin(_localMonths), itMonths - shift)); - return (index >= documents.size()) ? fallback : documents[index]; + const auto index = int(std::distance(begin(pack.dividers), it - shift)); + return (index >= pack.documents.size()) + ? fallback + : pack.documents[index]; } -Data::FileOrigin GiftBoxPack::origin(Type type) const { - const auto it = _setsData.find(type); - if (it == _setsData.end()) { - return Data::FileOrigin(); - } - return Data::FileOriginStickerSet( - it->second.setId, - it->second.accessHash); +Data::FileOrigin GiftBoxPack::origin() const { + return Data::FileOriginStickerSet(_premium.id, _premium.accessHash); } -void GiftBoxPack::load(Type type) { - if (_requestId) { +Data::FileOrigin GiftBoxPack::tonOrigin() const { + return Data::FileOriginStickerSet(_ton.id, _ton.accessHash); +} + +void GiftBoxPack::load() { + load(_premium, MTP_inputStickerSetPremiumGifts()); +} + +void GiftBoxPack::tonLoad() { + load(_ton, MTP_inputStickerSetTonGifts()); +} + +void GiftBoxPack::load(Pack &pack, const MTPInputStickerSet &set) { + if (pack.requestId || !pack.documents.empty()) { return; } - - const auto it = _setsData.find(type); - if (it != _setsData.end() && !it->second.documents.empty()) { - return; - } - - _requestId = _session->api().request(MTPmessages_GetStickerSet( - type == Type::Currency - ? MTP_inputStickerSetTonGifts() - : MTP_inputStickerSetPremiumGifts(), + pack.requestId = _session->api().request(MTPmessages_GetStickerSet( + set, MTP_int(0) // Hash. - )).done([=](const MTPmessages_StickerSet &result) { - _requestId = 0; + )).done([=, &pack](const MTPmessages_StickerSet &result) { + pack.requestId = 0; result.match([&](const MTPDmessages_stickerSet &data) { - applySet(data, type); + applySet(pack, data); }, [](const MTPDmessages_stickerSetNotModified &) { LOG(("API Error: Unexpected messages.stickerSetNotModified.")); }); - }).fail([=] { - _requestId = 0; + }).fail([=, &pack] { + pack.requestId = 0; }).send(); } -void GiftBoxPack::applySet(const MTPDmessages_stickerSet &data, Type type) { - auto setData = SetData(); - setData.setId = data.vset().data().vid().v; - setData.accessHash = data.vset().data().vaccess_hash().v; - +void GiftBoxPack::applySet(Pack &pack, const MTPDmessages_stickerSet &data) { + pack.id = data.vset().data().vid().v; + pack.accessHash = data.vset().data().vaccess_hash().v; auto documents = base::flat_map>(); for (const auto &sticker : data.vdocuments().v) { const auto document = _session->data().processDocument(sticker); if (document->sticker()) { documents.emplace(document->id, document); - if (setData.documents.empty()) { + if (pack.documents.empty()) { // Fallback. - setData.documents.resize(1); - setData.documents[0] = document; + pack.documents.resize(1); + pack.documents[0] = document; } } } - - for (const auto &pack : data.vpacks().v) { - pack.match([&](const MTPDstickerPack &data) { - const auto emoji = qs(data.vemoticon()); - if (emoji.isEmpty()) { - return; - } - for (const auto &id : data.vdocuments().v) { - if (const auto document = documents.take(id.v)) { - if (const auto sticker = (*document)->sticker()) { - if (!sticker->alt.isEmpty()) { - const auto ch = int(sticker->alt[0].unicode()); - const auto index = (ch - '1'); // [0, 4]; - if (index < 0 || index >= _localMonths.size()) { - return; - } - if ((index + 1) > setData.documents.size()) { - setData.documents.resize((index + 1)); - } - setData.documents[index] = (*document); + for (const auto &info : data.vpacks().v) { + const auto &data = info.data(); + const auto emoji = qs(data.vemoticon()); + if (emoji.isEmpty()) { + return; + } + for (const auto &id : data.vdocuments().v) { + if (const auto document = documents.take(id.v)) { + if (const auto sticker = (*document)->sticker()) { + if (!sticker->alt.isEmpty()) { + const auto ch = int(sticker->alt[0].unicode()); + const auto index = (ch - '1'); // [0, 4]; + if (index < 0 || index >= pack.dividers.size()) { + return; } + if ((index + 1) > pack.documents.size()) { + pack.documents.resize((index + 1)); + } + pack.documents[index] = (*document); } } } - }); + } } - - _setsData[type] = std::move(setData); - _updated.fire({}); + pack.updated.fire({}); } } // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h index 4664d895f2..728b10ddb4 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.h @@ -21,38 +21,45 @@ namespace Stickers { class GiftBoxPack final { public: - enum class Type { - Gifts, - Currency, - }; - explicit GiftBoxPack(not_null session); ~GiftBoxPack(); - void load(Type type = Type::Gifts); + void load(); [[nodiscard]] int monthsForStars(int stars) const; - [[nodiscard]] DocumentData *lookup( - int months, - Type type = Type::Gifts) const; - [[nodiscard]] Data::FileOrigin origin(Type type = Type::Gifts) const; + [[nodiscard]] DocumentData *lookup(int months) const; + [[nodiscard]] Data::FileOrigin origin() const; [[nodiscard]] rpl::producer<> updated() const; + void tonLoad(); + [[nodiscard]] DocumentData *tonLookup(int amount) const; + [[nodiscard]] Data::FileOrigin tonOrigin() const; + [[nodiscard]] rpl::producer<> tonUpdated() const; + private: using SetId = uint64; - struct SetData { - SetId setId = 0; + + struct Pack { + SetId id = 0; uint64 accessHash = 0; std::vector documents; + mtpRequestId requestId = 0; + std::vector dividers; + rpl::event_stream<> updated; }; - void applySet(const MTPDmessages_stickerSet &data, Type type); + void load(Pack &pack, const MTPInputStickerSet &set); + void applySet(Pack &pack, const MTPDmessages_stickerSet &data); + [[nodiscard]] DocumentData *lookup( + const Pack &pack, + int divider, + bool exact) const; const not_null _session; const std::vector _localMonths; + const std::vector _localTonAmounts; - rpl::event_stream<> _updated; - base::flat_map _setsData; - mtpRequestId _requestId = 0; + Pack _premium; + Pack _ton; }; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 20566113af..6b141e921c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -5768,6 +5768,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { auto result = PreparedServiceText(); const auto isSelf = (_from->id == _from->session().userPeerId()); const auto peer = isSelf ? _history->peer : _from; + _history->session().giftBoxStickersPacks().tonLoad(); const auto amount = action.vamount().v; const auto currency = qs(action.vcurrency()); const auto cost = AmountAndStarCurrency( diff --git a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp index 7f3e132cbf..93aa428774 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_giveaway.cpp @@ -48,7 +48,7 @@ auto GenerateGiveawayStart( return Data{ .sticker = packs.lookup(months), .size = st::msgServiceGiftBoxStickerSize, - .singleTimePlayback = true, + .stopOnLastFrame = true, }; }; push(std::make_unique( @@ -222,7 +222,7 @@ auto GenerateGiveawayResults( .sticker = packs.lookup(emoji, 0), .skipTop = st::chatGiveawayWinnersTopSkip, .size = st::maxAnimatedEmojiSize, - .singleTimePlayback = true, + .stopOnLastFrame = true, }; }; push(std::make_unique( diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp index 1e2bc404d5..8f1629f8fd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp @@ -474,8 +474,8 @@ void StickerInBubblePart::ensureCreated(Element *replacing) const { _link = data.link; _skipTop = data.skipTop; _sticker.emplace(_parent, sticker, skipPremiumEffect, replacing); - if (data.singleTimePlayback) { - _sticker->setPlayingOnce(true); + if (data.stopOnLastFrame) { + _sticker->setStopOnLastFrame(true); } _sticker->initSize(data.size); _sticker->setCustomCachingTag(data.cacheTag); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.h b/Telegram/SourceFiles/history/view/media/history_view_media_generic.h index e7b3b6b186..a1f576b4b6 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.h @@ -197,7 +197,7 @@ public: int skipTop = 0; int size = 0; ChatHelpers::StickerLottieSize cacheTag = {}; - bool singleTimePlayback = false; + bool stopOnLastFrame = false; ClickHandlerPtr link; explicit operator bool() const { 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 132b005ca9..b4ec167ae3 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "boxes/gift_premium_box.h" // ResolveGiftCode #include "chat_helpers/stickers_gift_box_pack.h" -#include "chat_helpers/stickers_lottie.h" #include "core/click_handler_types.h" // ClickHandlerContext #include "data/stickers/data_custom_emoji.h" #include "data/data_channel.h" @@ -30,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_credits_graphics.h" // GiftedCreditsBox #include "settings/settings_premium.h" // Settings::ShowGiftPremium #include "ui/chat/chat_style.h" +#include "ui/controls/ton_common.h" // kNanosInOne #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "window/window_session_controller.h" @@ -416,15 +416,17 @@ void PremiumGift::ensureStickerCreated() const { if (_sticker) { return; } else if (tonGift()) { - const auto document = ChatHelpers::GenerateLocalTgsSticker( - &_parent->history()->session(), - "diamond"); - const auto sticker = document->sticker(); - Assert(sticker != nullptr); - _sticker.emplace(_parent, document, false, _parent); - _sticker->setPlayingOnce(true); - _sticker->initSize(st::msgServiceStarGiftStickerSize); - _parent->repaint(); + const auto &session = _parent->history()->session(); + auto &packs = session.giftBoxStickersPacks(); + const auto count = _data.count / Ui::kNanosInOne; + if (const auto document = packs.tonLookup(count)) { + if (document->sticker()) { + const auto skipPremiumEffect = false; + _sticker.emplace(_parent, document, skipPremiumEffect, _parent); + _sticker->setStopOnLastFrame(true); + _sticker->initSize(st::msgServiceGiftBoxStickerSize); + } + } return; } else if (const auto document = _data.document) { const auto sticker = document->sticker(); @@ -443,7 +445,7 @@ void PremiumGift::ensureStickerCreated() const { if (document->sticker()) { const auto skipPremiumEffect = false; _sticker.emplace(_parent, document, skipPremiumEffect, _parent); - _sticker->setPlayingOnce(true); + _sticker->setStopOnLastFrame(true); _sticker->initSize(st::msgServiceGiftBoxStickerSize); } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index a63541e0f2..3299a8735b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -168,7 +168,7 @@ QSize Sticker::countOptimalSize() { } bool Sticker::readyToDrawAnimationFrame() { - if (!_lastDiceFrame.isNull()) { + if (!_lastFrameCached.isNull()) { return true; } const auto sticker = _data->sticker(); @@ -261,7 +261,7 @@ void Sticker::paintAnimationFrame( const QRect &r) { const auto colored = (customEmojiPart() && _data->emojiUsesTextColor()) ? ComputeEmojiTextColor(context) - : (context.selected() && !_nextLastDiceFrame) + : (context.selected() && !_nextLastFrame) ? context.st->msgStickerOverlay()->c : QColor(0, 0, 0, 0); const auto powerSavingFlag = (emojiSticker() || _diceIndex >= 0) @@ -276,14 +276,16 @@ void Sticker::paintAnimationFrame( context.now, paused) : StickerPlayer::FrameInfo(); - if (_nextLastDiceFrame) { - _nextLastDiceFrame = false; - _lastDiceFrame = CacheDiceImage(_diceEmoji, _diceIndex, frame.image); + if (_nextLastFrame) { + _nextLastFrame = false; + _lastFrameCached = (_diceIndex > 0) + ? CacheDiceImage(_diceEmoji, _diceIndex, frame.image) + : frame.image; } - const auto &image = _lastDiceFrame.isNull() + const auto &image = _lastFrameCached.isNull() ? frame.image - : _lastDiceFrame; - const auto prepared = (!_lastDiceFrame.isNull() && context.selected()) + : _lastFrameCached; + const auto prepared = (!_lastFrameCached.isNull() && context.selected()) ? Images::Colored( base::duplicate(image), context.st->msgStickerOverlay()->c) @@ -296,25 +298,25 @@ void Sticker::paintAnimationFrame( r.y() + (r.height() - size.height()) / 2), size), prepared); - if (!_lastDiceFrame.isNull()) { + if (!_lastFrameCached.isNull()) { return; } const auto count = _player->framesCount(); _frameIndex = frame.index; _framesCount = count; - _nextLastDiceFrame = !paused - && (_diceIndex > 0) + _nextLastFrame = !paused + && _stopOnLastFrame && (_frameIndex + 2 == count); - const auto playOnce = (_playingOnce || _diceIndex > 0) + const auto playOnce = _playingOnce ? true : (_diceIndex == 0) ? false : ((!customEmojiPart() && emojiSticker()) || !Core::App().settings().loopAnimatedStickers()); - const auto lastDiceFrame = (_diceIndex > 0) && atTheEnd(); + const auto lastFrame = _stopOnLastFrame && atTheEnd(); const auto switchToNext = !playOnce - || (!lastDiceFrame && (_frameIndex != 0 || !_oncePlayed)); + || (!lastFrame && (_frameIndex != 0 || !_oncePlayed)); if (!paused && switchToNext && _player->markFrameShown() @@ -519,12 +521,19 @@ void Sticker::dataMediaCreated() const { void Sticker::setDiceIndex(const QString &emoji, int index) { _diceEmoji = emoji; _diceIndex = index; + _playingOnce = (index >= 0); + _stopOnLastFrame = (index > 0); } void Sticker::setPlayingOnce(bool once) { _playingOnce = once; } +void Sticker::setStopOnLastFrame(bool stop) { + _stopOnLastFrame = stop; + _playingOnce = true; +} + void Sticker::setCustomCachingTag(ChatHelpers::StickerLottieSize tag) { _cachingTag = tag; } @@ -595,8 +604,8 @@ void Sticker::unloadPlayer() { if (!_player) { return; } - if (_diceIndex > 0 && _lastDiceFrame.isNull()) { - _nextLastDiceFrame = false; + if (_stopOnLastFrame && _lastFrameCached.isNull()) { + _nextLastFrame = false; _oncePlayed = false; } _player = nullptr; diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.h b/Telegram/SourceFiles/history/view/media/history_view_sticker.h index d2709d1539..629d330311 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.h +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.h @@ -67,6 +67,7 @@ public: void setDiceIndex(const QString &emoji, int index); void setPlayingOnce(bool once); + void setStopOnLastFrame(bool stop); void setCustomCachingTag(ChatHelpers::StickerLottieSize tag); void setCustomEmojiPart(); void setEmojiSticker(); @@ -128,7 +129,7 @@ private: mutable std::shared_ptr _dataMedia; ClickHandlerPtr _link; QSize _size; - QImage _lastDiceFrame; + QImage _lastFrameCached; QString _diceEmoji; int _diceIndex = -1; mutable int _frameIndex = -1; @@ -137,12 +138,13 @@ private: mutable bool _oncePlayed : 1 = false; mutable bool _premiumEffectPlayed : 1 = false; mutable bool _premiumEffectSkipped : 1 = false; - mutable bool _nextLastDiceFrame : 1 = false; + mutable bool _nextLastFrame : 1 = false; bool _skipPremiumEffect : 1 = false; bool _customEmojiPart : 1 = false; bool _emojiSticker : 1 = false; bool _webpagePart : 1 = false; bool _playingOnce : 1 = false; + bool _stopOnLastFrame : 1 = false; }; diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp index b3550718b8..9e1ba75d52 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_format.cpp @@ -67,7 +67,6 @@ QString ToUsd( int afterFloat) { constexpr auto kApproximately = QChar(0x2248); - const auto result = int64(base::SafeRound(value.value() * rate)); return QString(kApproximately) + QChar('$') + QString::number( diff --git a/Telegram/SourceFiles/settings/settings_credits.cpp b/Telegram/SourceFiles/settings/settings_credits.cpp index bdd4157bf8..1ed8c28c51 100644 --- a/Telegram/SourceFiles/settings/settings_credits.cpp +++ b/Telegram/SourceFiles/settings/settings_credits.cpp @@ -121,8 +121,7 @@ Credits::Credits( st::tonFieldIconSize, st::currencyFg->c) : Ui::GenerateStars(st::creditsBalanceStarHeight, 1)) { - _controller->session().giftBoxStickersPacks().load( - Stickers::GiftBoxPack::Type::Currency); + _controller->session().giftBoxStickersPacks().tonLoad(); setupContent(); _controller->session().premiumPossibleValue( @@ -418,7 +417,6 @@ void Credits::setupContent() { }; const auto state = content->lifetime().make_state(); - const auto paddings = rect::m::sum::h(st::boxRowPadding); { const auto button = content->add( object_ptr>( @@ -623,13 +621,13 @@ QPointer Credits::createPinnedToTop( st::creditsPremiumCover, Ui::Premium::TopBarDescriptor{ .clickContextOther = clickContextOther, + .logo = isCurrency ? u"diamond"_q : QString(), .title = title(), .about = (isCurrency ? tr::lng_credits_currency_summary_about : tr::lng_credits_summary_about)( TextWithEntities::Simple), .light = true, - .logo = isCurrency ? u"diamond"_q : QString(), .gradientStops = Ui::Premium::CreditsIconGradientStops(), }); }(); diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 448a3a9f2f..0632cf18b1 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -1311,13 +1311,12 @@ void GenericCreditsEntryBox( auto &packs = session->giftBoxStickersPacks(); const auto document = starGiftSticker ? starGiftSticker + : e.credits.ton() + ? packs.tonLookup(e.credits.whole()) : packs.lookup( e.premiumMonthsForStars ? e.premiumMonthsForStars - : packs.monthsForStars(e.credits.whole()), - e.credits.stars() - ? Stickers::GiftBoxPack::Type::Gifts - : Stickers::GiftBoxPack::Type::Currency); + : packs.monthsForStars(e.credits.whole())); if (document && document->sticker()) { state->sticker = document; state->media = document->createMediaView();