From 312d5f0121727a4dfe8093831f966f526db847af Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Nov 2025 19:04:50 +0400 Subject: [PATCH] Improve auction gift display. --- Telegram/Resources/langs/lang.strings | 2 +- .../SourceFiles/boxes/gift_premium_box.cpp | 9 ++++ .../boxes/star_gift_auction_box.cpp | 17 +++++++- Telegram/SourceFiles/data/data_credits.h | 1 + Telegram/SourceFiles/data/data_media_types.h | 2 + Telegram/SourceFiles/data/data_session.cpp | 8 ++++ Telegram/SourceFiles/data/data_session.h | 7 ++++ Telegram/SourceFiles/history/history.cpp | 7 ++++ Telegram/SourceFiles/history/history_item.cpp | 41 ++++++++++--------- .../view/media/history_view_premium_gift.cpp | 25 +++++++---- .../settings/settings_credits_graphics.cpp | 8 +++- 11 files changed, 97 insertions(+), 30 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 170bedb506..a3a51bfd72 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2293,7 +2293,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_action_gift_sent_self_channel" = "You sent a gift to {name} for {cost}"; "lng_action_gift_self_bought" = "You bought a gift for {cost}"; "lng_action_gift_self_auction" = "You've successfully bought a gift in the auction for {cost}."; -"lng_action_gift_auction" = "You've successfully bought a gift for {name} in the auction for {cost}."; +"lng_action_gift_auction_won" = "You won the auction with a bid of {cost}."; "lng_action_gift_self_subtitle" = "Saved Gift"; "lng_action_gift_self_about#one" = "Display this gift on your page or convert it to **{count}** Star."; "lng_action_gift_self_about#other" = "Display this gift on your page or convert it to **{count}** Stars."; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 60ee15bc81..131ab4f86f 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -1328,6 +1328,15 @@ void AddStarGiftTable( PeerId(entry.bareEntryOwnerId)), st::giveawayGiftCodePeerMargin); } + } else if (entry.auction && entry.bareGiftOwnerId) { + AddTableRow( + table, + tr::lng_credits_box_history_entry_peer(), + MakePeerTableValue( + table, + show, + PeerId(entry.bareGiftOwnerId)), + st::giveawayGiftCodePeerMargin); } else if (peerId && !giftToSelf) { const auto user = session->data().peer(peerId)->asUser(); const auto withSendButton = entry.in && user && !user->isBot(); diff --git a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp index 05e667eee9..6d56bf093f 100644 --- a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/components/credits.h" #include "data/components/gift_auctions.h" #include "data/data_message_reactions.h" +#include "data/data_session.h" #include "data/data_user.h" #include "history/view/controls/history_view_suggest_options.h" #include "info/channel_statistics/earn/earn_icons.h" @@ -407,7 +408,9 @@ void AddBidPlaces( top.reserve(3); const auto pushTop = [&](auto i) { const auto index = int(i - begin(levels)); - if (top.size() < 3 && index < value.topBidders.size()) { + if (top.size() < 3 + && index < value.topBidders.size() + && !value.topBidders[index]->isSelf()) { top.push_back({ value.topBidders[index], int(i->amount) }); return true; } @@ -553,7 +556,19 @@ void AuctionBidBox(not_null box, AuctionBidBoxArgs &&args) { const auto chosen = mine ? mine : std::clamp(mine, min, max); state->chosen = chosen; + const auto giftId = now.gift->id; const auto show = args.show; + args.peer->owner().giftAuctionGots( + ) | rpl::start_with_next([=](const Data::GiftAuctionGot &update) { + if (update.giftId == giftId) { + box->closeBox(); + + if (const auto window = show->resolveWindow()) { + window->showPeer(update.to, ShowAtTheEndMsgId); + } + } + }, box->lifetime()); + const auto details = args.details ? *args.details : std::optional(); diff --git a/Telegram/SourceFiles/data/data_credits.h b/Telegram/SourceFiles/data/data_credits.h index 3b1e810eb2..e72478c2af 100644 --- a/Telegram/SourceFiles/data/data_credits.h +++ b/Telegram/SourceFiles/data/data_credits.h @@ -104,6 +104,7 @@ struct CreditsHistoryEntry final { bool converted : 1 = false; bool anonymous : 1 = false; bool stargift : 1 = false; + bool auction : 1 = false; bool postsSearch : 1 = false; bool giftTransferred : 1 = false; bool giftRefunded : 1 = false; diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index df65a73add..f9dc692deb 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -149,6 +149,7 @@ struct GiftCode { PeerData *stargiftReleasedBy = nullptr; std::shared_ptr unique; TextWithEntities message; + PeerData *auctionTo = nullptr; ChannelData *channel = nullptr; PeerData *channelFrom = nullptr; uint64 channelSavedId = 0; @@ -159,6 +160,7 @@ struct GiftCode { int starsToUpgrade = 0; int starsUpgradedBySender = 0; int starsForDetailsRemove = 0; + int starsBid = 0; int limitedCount = 0; int limitedLeft = 0; int64 count = 0; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 4b94c6501f..3cec63f96f 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1877,6 +1877,14 @@ rpl::producer Session::giftsUpdates() const { return _giftsUpdates.events(); } +void Session::notifyGiftAuctionGot(GiftAuctionGot &&update) { + _giftAuctionGots.fire(std::move(update)); +} + +rpl::producer Session::giftAuctionGots() const { + return _giftAuctionGots.events(); +} + HistoryItem *Session::changeMessageId(PeerId peerId, MsgId wasId, MsgId nowId) { const auto list = messagesListForInsert(peerId); const auto i = list->find(wasId); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 6b52735d3a..d62524093e 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -115,6 +115,10 @@ struct GiftsUpdate { std::vector added; std::vector removed; }; +struct GiftAuctionGot { + uint64 giftId = 0; + not_null to; +}; struct SentToScheduled { not_null history; @@ -361,6 +365,8 @@ public: [[nodiscard]] rpl::producer giftUpdates() const; void notifyGiftsUpdate(GiftsUpdate &&update); [[nodiscard]] rpl::producer giftsUpdates() const; + void notifyGiftAuctionGot(GiftAuctionGot &&update); + [[nodiscard]] rpl::producer giftAuctionGots() const; void requestItemRepaint(not_null item); [[nodiscard]] rpl::producer> itemRepaintRequest() const; void requestViewRepaint(not_null view); @@ -1075,6 +1081,7 @@ private: rpl::event_stream> _newItemAdded; rpl::event_stream _giftUpdates; rpl::event_stream _giftsUpdates; + rpl::event_stream _giftAuctionGots; rpl::event_stream> _itemRepaintRequest; rpl::event_stream> _viewRepaintRequest; rpl::event_stream> _itemResizeRequest; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 63393d2d49..07e7063d88 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1373,6 +1373,13 @@ void History::applyServiceChanges( } } } + }, [&](const MTPDmessageActionStarGift &data) { + if (data.is_auction_acquired() && data.vto_id()) { + const auto to = peer->owner().peer(peerFromMTP(*data.vto_id())); + data.vgift().match([&](const MTPDstarGift &data) { + peer->owner().notifyGiftAuctionGot({ data.vid().v, to }); + }, [](const auto &) {}); + } }, [](const auto &) { }); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index a4ab5d14ea..8fb334b348 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -6065,29 +6065,15 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { } } } else if (anonymous || _history->peer->isSelf()) { - const auto to = (action.is_auction_acquired() && action.vto_id()) - ? peer->owner().peer(peerFromMTP(*action.vto_id())).get() - : nullptr; - result.text = to - ? tr::lng_action_gift_auction( + result.text = (action.is_auction_acquired() + ? tr::lng_action_gift_auction_won + : anonymous + ? tr::lng_action_gift_received_anonymous + : tr::lng_action_gift_self_bought)( tr::now, - lt_name, - Ui::Text::Link(to->shortName(), 1), lt_cost, cost, - Ui::Text::WithEntities) - : (action.is_auction_acquired() - ? tr::lng_action_gift_self_auction - : anonymous - ? tr::lng_action_gift_received_anonymous - : tr::lng_action_gift_self_bought)( - tr::now, - lt_cost, - cost, - Ui::Text::WithEntities); - if (to) { - result.links.push_back(to->createOpenLink()); - } + tr::marked); } else if (upgradeGifted) { // Who sent the gift. const auto fromId = action.vfrom_id() @@ -6636,6 +6622,14 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { : PeerId(); const auto upgradeMsgId = data.vupgrade_msg_id().value_or_empty(); const auto realGiftMsgId = data.vgift_msg_id().value_or_empty(); + const auto bid = data.vgift().match([&](const MTPDstarGift &gift) { + return data.is_auction_acquired() + ? (int(gift.vstars().v) + + int(gift.vupgrade_stars().value_or_empty())) + : 0; + }, [](const MTPDstarGiftUnique &) { + return 0; + }); using Fields = Data::GiftCode; auto fields = Fields{ .message = (data.vmessage() @@ -6643,6 +6637,12 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { &history()->session(), *data.vmessage()) : TextWithEntities()), + .auctionTo = (service + && data.is_auction_acquired() + && data.vto_id()) + ? history()->owner().peer( + peerFromMTP(*data.vto_id())).get() + : nullptr, .channel = ((service && peerIsChannel(to)) ? history()->owner().channel(peerToChannel(to)).get() : nullptr), @@ -6656,6 +6656,7 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { .starsConverted = int(data.vconvert_stars().value_or_empty()), .starsUpgradedBySender = int( data.vupgrade_stars().value_or_empty()), + .starsBid = bid, .type = Data::GiftType::StarGift, .upgradeSeparate = data.is_upgrade_separate(), .upgradable = data.is_can_upgrade(), 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 34e4d28ec0..fca6153188 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -78,6 +78,7 @@ TextWithEntities PremiumGift::title() { Ui::Text::WithEntities); } else if (starGift()) { const auto peer = _parent->history()->peer; + const auto to = _data.auctionTo ? _data.auctionTo : peer.get(); return peer->isSelf() ? tr::lng_action_gift_self_subtitle(tr::now, WithEntities) : (peer->isServiceUser() && _data.channelFrom) @@ -91,7 +92,7 @@ TextWithEntities PremiumGift::title() { .append(' ') .append(_data.channelFrom->shortName()), WithEntities) - : peer->isServiceUser() + : (!_data.auctionTo && peer->isServiceUser()) ? tr::lng_gift_link_label_gift(tr::now, WithEntities) : (outgoingGift() ? tr::lng_action_gift_sent_subtitle @@ -100,10 +101,10 @@ TextWithEntities PremiumGift::title() { lt_user, WithEntities({}) .append(SingleCustomEmoji( - peer->owner().customEmojiManager( - ).peerUserpicEmojiData(peer))) + to->owner().customEmojiManager( + ).peerUserpicEmojiData(to))) .append(' ') - .append(peer->shortName()), + .append(to->shortName()), WithEntities); } else if (creditsPrize()) { return tr::lng_prize_title(tr::now, WithEntities); @@ -144,7 +145,17 @@ TextWithEntities PremiumGift::subtitle() { : _data.refunded ? tr::lng_action_gift_refunded(tr::now, Ui::Text::RichLangValue) : outgoingGift() - ? (_data.starsUpgradedBySender + ? (_data.auctionTo + ? tr::lng_action_gift_self_auction( + tr::now, + lt_cost, + tr::lng_action_gift_for_stars( + tr::now, + lt_count, + _data.starsBid, + tr::marked), + tr::rich) + : _data.starsUpgradedBySender ? tr::lng_action_gift_sent_upgradable( tr::now, lt_user, @@ -423,12 +434,12 @@ void PremiumGift::unloadHeavyPart() { bool PremiumGift::incomingGift() const { const auto out = _parent->data()->out(); - return gift() && (starGiftUpgrade() ? out : !out); + return gift() && !_data.auctionTo && (starGiftUpgrade() ? out : !out); } bool PremiumGift::outgoingGift() const { const auto out = _parent->data()->out(); - return gift() && (starGiftUpgrade() ? !out : out); + return gift() && (_data.auctionTo || (starGiftUpgrade() ? !out : out)); } bool PremiumGift::gift() const { diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index a1a698d8a3..d2597ec810 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -2666,9 +2666,14 @@ void ShowStarGiftViewBox( const auto peer = item->history()->peer; const auto toChannel = peer->isServiceUser() && data.channel; const auto incoming = !toChannel + && !data.auctionTo && (data.upgrade ? item->out() : !item->out()); const auto fromId = incoming ? peer->id : peer->session().userPeerId(); - const auto toId = incoming ? peer->session().userPeerId() : peer->id; + const auto toId = incoming + ? peer->session().userPeerId() + : data.auctionTo + ? data.auctionTo->id + : peer->id; const auto ownerId = data.unique ? data.unique->ownerId : toId; const auto hostId = data.unique ? data.unique->hostId : PeerId(); const auto nextToUpgradeStickerId = upgradeNext @@ -2713,6 +2718,7 @@ void ShowStarGiftViewBox( .converted = data.converted, .anonymous = data.anonymous, .stargift = true, + .auction = (data.auctionTo != nullptr), .giftTransferred = data.transferred, .giftRefunded = data.refunded, .giftUpgradeSeparate = data.upgradeSeparate,