diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 17840c510c..2d00c68e7b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3759,6 +3759,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_resale_symbol" = "Symbol"; "lng_gift_resale_symbols#one" = "{count} Symbol"; "lng_gift_resale_symbols#other" = "{count} Symbols"; +"lng_gift_resale_switch_to" = "Switch to {currency}"; "lng_gift_resale_early" = "You will be able to resell this gift in {duration}."; "lng_gift_transfer_early" = "You will be able to transfer this gift in {duration}."; "lng_gift_resale_transfer_early_title" = "Try Later"; diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index d28b5d536d..34ec652710 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -2842,7 +2842,10 @@ void SendGiftBox( Settings::GlobalStarGiftBox, window->uiShow(), star->info, - peer->id, + Settings::StarGiftResaleInfo{ + .recipientId = peer->id, + .forceTon = star->forceTon, + }, Settings::CreditsEntryBoxStyleOverrides())); } else if (star && star->resale) { const auto id = star->info.id; @@ -3232,7 +3235,6 @@ void GiftResaleBox( not_null peer, ResaleGiftsDescriptor descriptor) { box->setWidth(st::boxWideWidth); - box->addButton(tr::lng_create_group_back(), [=] { box->closeBox(); }); // Create a proper vertical layout for the title const auto titleWrap = box->setPinnedToTopContent( @@ -3273,12 +3275,29 @@ void GiftResaleBox( rpl::event_stream<> updated; ResaleGiftsDescriptor data; rpl::variable filter; + rpl::variable ton; rpl::lifetime loading; int lastMinHeight = 0; }; const auto state = content->lifetime().make_state(); state->data = std::move(descriptor); + box->addButton(tr::lng_create_group_back(), [=] { box->closeBox(); }); + +#ifndef OS_MAC_STORE + const auto currency = box->addLeftButton(rpl::single(QString()), [=] { + state->ton = !state->ton.current(); + state->updated.fire({}); + }); + currency->setText(tr::lng_gift_resale_switch_to( + lt_currency, + rpl::conditional( + state->ton.value(), + rpl::single(Ui::Text::IconEmoji(&st::starIconEmoji)), + rpl::single(Ui::Text::IconEmoji(&st::tonIconEmoji))), + Ui::Text::WithEntities)); +#endif + box->heightValue() | rpl::start_with_next([=](int height) { if (height > state->lastMinHeight) { state->lastMinHeight = height; @@ -3340,9 +3359,11 @@ void GiftResaleBox( ) | rpl::map([=] { auto result = GiftsDescriptor(); const auto selfId = window->session().userPeerId(); + const auto forceTon = state->ton.current(); for (const auto &gift : state->data.list) { result.list.push_back(GiftTypeStars{ .info = gift, + .forceTon = forceTon, .resale = true, .mine = (gift.unique->ownerId == selfId), }); diff --git a/Telegram/SourceFiles/boxes/transfer_gift_box.cpp b/Telegram/SourceFiles/boxes/transfer_gift_box.cpp index 2b697bcbdb..598c2a4744 100644 --- a/Telegram/SourceFiles/boxes/transfer_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/transfer_gift_box.cpp @@ -676,6 +676,7 @@ void ShowTransferGiftBox( void ShowBuyResaleGiftBox( std::shared_ptr show, std::shared_ptr gift, + bool forceTon, not_null to, Fn closeParentBox) { show->show(Box([=](not_null box) { @@ -684,7 +685,7 @@ void ShowBuyResaleGiftBox( bool sent = false; }; const auto state = std::make_shared(); - state->ton = gift->onlyAcceptTon; + state->ton = gift->onlyAcceptTon || forceTon; if (gift->onlyAcceptTon) { box->addRow( @@ -699,7 +700,9 @@ void ShowBuyResaleGiftBox( object_ptr( box, Ui::SubTabsOptions{ - .selected = u"stars"_q, + .selected = (state->ton.current() + ? u"ton"_q + : u"stars"_q), .centered = true, }, std::vector{ diff --git a/Telegram/SourceFiles/boxes/transfer_gift_box.h b/Telegram/SourceFiles/boxes/transfer_gift_box.h index 27430b43e6..cab7aee2b4 100644 --- a/Telegram/SourceFiles/boxes/transfer_gift_box.h +++ b/Telegram/SourceFiles/boxes/transfer_gift_box.h @@ -35,6 +35,7 @@ void ShowTransferGiftBox( void ShowBuyResaleGiftBox( std::shared_ptr show, std::shared_ptr gift, + bool forceTon, not_null to, Fn closeParentBox); diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index ec18169166..b2481979f6 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -1945,7 +1945,12 @@ void ResolveAndShowUniqueGift( session->data().processUsers(data.vusers()); if (const auto gift = Api::FromTL(session, data.vgift())) { using namespace ::Settings; - show->show(Box(GlobalStarGiftBox, show, *gift, PeerId(), st)); + show->show(Box( + GlobalStarGiftBox, + show, + *gift, + StarGiftResaleInfo(), + st)); } }).fail([=](const MTP::Error &error) { clear(); diff --git a/Telegram/SourceFiles/data/data_credits.h b/Telegram/SourceFiles/data/data_credits.h index 0b0b9382ed..b8d6d7f92d 100644 --- a/Telegram/SourceFiles/data/data_credits.h +++ b/Telegram/SourceFiles/data/data_credits.h @@ -102,6 +102,7 @@ struct CreditsHistoryEntry final { bool giftRefunded : 1 = false; bool giftUpgraded : 1 = false; bool giftResale : 1 = false; + bool giftResaleForceTon : 1 = false; bool giftPinned : 1 = false; bool savedToProfile : 1 = false; bool fromGiftsList : 1 = false; diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp index abeb1ec173..ee5139cfc4 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp @@ -92,10 +92,9 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { if (_descriptor == descriptor && _resalePrice == resalePrice) { return; } - auto player = base::take(_player); const auto starsType = Ui::Premium::MiniStarsType::SlowStars; - _mediaLifetime.destroy(); unsubscribe(); + update(); const auto format = [=](int64 number) { const auto onlyK = (number < 100'000'000); @@ -161,13 +160,15 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { _price.setMarkedText( st::semiboldTextStyle, (data.resale - ? (unique + ? ((unique && data.forceTon) + ? Data::FormatGiftResaleTon(*unique) + : (unique ? _delegate->monostar() - : _delegate->star()).append(' ').append( - format(unique - ? unique->starsForResale - : data.info.starsResellMin) - ).append(data.info.resellCount > 1 ? "+" : "") + : _delegate->star()).append(' ').append( + format(unique + ? unique->starsForResale + : data.info.starsResellMin) + ).append(data.info.resellCount > 1 ? "+" : "")) : (_small && unique && unique->starsForResale) ? Data::FormatGiftResaleAsked(*unique) : unique @@ -196,11 +197,18 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { Ui::Premium::CreditsIconGradientStops()); } }); - _delegate->sticker( + + _resolvedDocument = nullptr; + _documentLifetime = _delegate->sticker( descriptor ) | rpl::start_with_next([=](not_null document) { + _documentLifetime.destroy(); setDocument(document); - }, lifetime()); + }); + if (_resolvedDocument) { + _documentLifetime.destroy(); + } + _patterned = false; _uniqueBackgroundCache = QImage(); _uniquePatternEmoji = nullptr; @@ -232,16 +240,19 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { } } -bool GiftButton::documentResolved() const { - return _player || _mediaLifetime; -} - void GiftButton::setDocument(not_null document) { + _resolvedDocument = document; + if (_playerDocument == document) { + return; + } + const auto media = document->createMediaView(); media->checkStickerLarge(); media->goodThumbnailWanted(); - rpl::single() | rpl::then( + const auto destroyed = base::take(_player); + _playerDocument = nullptr; + _mediaLifetime = rpl::single() | rpl::then( document->owner().session().downloaderTaskFinished() ) | rpl::filter([=] { return media->loaded(); @@ -269,9 +280,13 @@ void GiftButton::setDocument(not_null document) { st::giftBoxStickerSize); } result->setRepaintCallback([=] { update(); }); + _playerDocument = media->owner(); _player = std::move(result); update(); - }, _mediaLifetime); + }); + if (_playerDocument) { + _mediaLifetime.destroy(); + } } void GiftButton::setGeometry(QRect inner, QMargins extend) { @@ -627,10 +642,11 @@ void GiftButton::paintEvent(QPaintEvent *e) { QSize(icon.width() + 2 * add, icon.height() + 2 * add)); p.drawEllipse(rect); icon.paintInCenter(p, rect); - } else if (unique->nanoTonForResale && unique->onlyAcceptTon) { + } else if (!data.forceTon + && unique->nanoTonForResale + && unique->onlyAcceptTon) { if (_tonIcon.isNull()) { - _tonIcon = Ui::Earn::IconCurrencyColored( - st::tonIconEmojiSize, + _tonIcon = st::tonIconEmoji.icon.instance( QColor(255, 255, 255)); } const auto size = _tonIcon.size() / _tonIcon.devicePixelRatio(); diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h index 07b5620675..4c16dbab78 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h @@ -65,6 +65,7 @@ struct GiftTypeStars { PeerData *from = nullptr; TimeId date = 0; bool pinnedSelection : 1 = false; + bool forceTon : 1 = false; bool userpic : 1 = false; bool pinned : 1 = false; bool hidden : 1 = false; @@ -160,7 +161,6 @@ private: int height); void setDocument(not_null document); - [[nodiscard]] bool documentResolved() const; [[nodiscard]] QMargins currentExtend() const; void unsubscribe(); @@ -188,8 +188,12 @@ private: QRect _button; QMargins _extend; + DocumentData *_resolvedDocument = nullptr; + std::unique_ptr _player; + DocumentData *_playerDocument = nullptr; rpl::lifetime _mediaLifetime; + rpl::lifetime _documentLifetime; }; diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index c314abd938..4196b62046 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -1235,14 +1235,17 @@ void GenericCreditsEntryBox( box->setNoContentMargin(true); const auto slug = uniqueGift->slug; + const auto forceTon = e.giftResaleForceTon; auto price = rpl::single( rpl::empty ) | rpl::then(session->data().giftUpdates( ) | rpl::filter([=](const Data::GiftUpdate &update) { return (update.action == Data::GiftUpdate::Action::ResaleChange) && (update.slug == slug); - }) | rpl::to_empty) | rpl::map([unique = e.uniqueGift] { - return Data::UniqueGiftResaleAsked(*unique); + }) | rpl::to_empty) | rpl::map([forceTon, unique = e.uniqueGift] { + return forceTon + ? Data::UniqueGiftResaleTon(*unique) + : Data::UniqueGiftResaleAsked(*unique); }); auto change = [=] { const auto style = st.giftWearBox @@ -2091,6 +2094,7 @@ void GenericCreditsEntryBox( ShowBuyResaleGiftBox( show, e.uniqueGift, + e.giftResaleForceTon, to, crl::guard(box, [=] { box->closeBox(); })); } else if (canUpgradeFree) { @@ -2102,7 +2106,7 @@ void GenericCreditsEntryBox( } }); if (canBuyResold) { - if (uniqueGift->onlyAcceptTon) { + if (uniqueGift->onlyAcceptTon || e.giftResaleForceTon) { button->setText(rpl::single(QString())); Ui::SetButtonTwoLabels( button, @@ -2205,7 +2209,7 @@ void GlobalStarGiftBox( not_null box, std::shared_ptr show, const Data::StarGift &data, - PeerId resaleRecipientId, + StarGiftResaleInfo resale, CreditsEntryBoxStyleOverrides st) { const auto selfId = show->session().userPeerId(); const auto ownerId = data.unique ? data.unique->ownerId.value : 0; @@ -2216,8 +2220,8 @@ void GlobalStarGiftBox( .credits = CreditsAmount(data.stars), .bareGiftStickerId = data.document->id, .bareGiftOwnerId = ownerId, - .bareGiftResaleRecipientId = ((resaleRecipientId != selfId) - ? resaleRecipientId.value + .bareGiftResaleRecipientId = ((resale.recipientId != selfId) + ? resale.recipientId.value : 0), .stargiftId = data.id, .uniqueGift = data.unique, @@ -2225,6 +2229,7 @@ void GlobalStarGiftBox( .limitedCount = data.limitedCount, .limitedLeft = data.limitedLeft, .stargift = true, + .giftResaleForceTon = resale.forceTon, .fromGiftSlug = true, .in = (ownerId == show->session().userPeerId().value), .gift = true, diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index 9789278fac..a2329e5902 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -155,11 +155,16 @@ void CreditsPrizeBox( not_null controller, const Data::GiftCode &data, TimeId date); + +struct StarGiftResaleInfo { + PeerId recipientId; + bool forceTon = false; +}; void GlobalStarGiftBox( not_null box, std::shared_ptr show, const Data::StarGift &data, - PeerId resaleRecipientId, + StarGiftResaleInfo resale, CreditsEntryBoxStyleOverrides st = {}); [[nodiscard]] Data::CreditsHistoryEntry SavedStarGiftEntry( diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index 8881c8bbb8..28b01272af 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -85,7 +85,6 @@ tonIconEmoji: IconEmoji { icon: icon{{ "payments/ton_emoji-18x18", currencyFg }}; padding: margins(0px, 1px, 0px, 0px); } -tonIconEmojiSize: 18px; creditsHistoryEntryTypeAds: icon {{ "folders/folders_channels", premiumButtonFg }};