From 80db076f382ab9961ba0247f6036c30aadc3e48b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 22 Jan 2025 22:12:50 +0400 Subject: [PATCH] Improve channel gifts viewing. --- Telegram/Resources/langs/lang.strings | 3 + Telegram/SourceFiles/api/api_premium.cpp | 1 + .../SourceFiles/boxes/gift_premium_box.cpp | 63 +++++++-- Telegram/SourceFiles/boxes/gift_premium_box.h | 8 ++ Telegram/SourceFiles/data/data_star_gift.h | 1 + .../view/media/history_view_premium_gift.cpp | 130 +++++++++++------- .../view/media/history_view_premium_gift.h | 2 + .../view/media/history_view_unique_gift.cpp | 20 +-- .../settings/settings_credits_graphics.cpp | 14 ++ 9 files changed, 156 insertions(+), 86 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b7f51f51e..3ffe1bbf6 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3298,6 +3298,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_visible_hint" = "This gift is visible on your page."; "lng_gift_hidden_hint_channel" = "This gift is hidden from visitors of your channel."; "lng_gift_visible_hint_channel" = "This gift is visible in your channel's Gifts."; +"lng_gift_in_blockchain" = "This gift is in TON blockchain. {link}"; +"lng_gift_in_blockchain_link" = "View >"; "lng_gift_visible_hide" = "Hide >"; "lng_gift_show_on_page" = "Display on my Page"; "lng_gift_show_on_channel" = "Display in channel's Gifts"; @@ -3309,6 +3311,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_channel_title" = "Send a Gift"; "lng_gift_channel_about" = "Select a gift to show appreciation for {name}."; "lng_gift_unique_owner" = "Owner"; +"lng_gift_unique_address_copied" = "Address copied to clipboard."; "lng_gift_unique_status" = "Status"; "lng_gift_unique_status_non" = "Non-Unique"; "lng_gift_unique_status_upgrade" = "upgrade"; diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index 177bda4e3..58b2d462e 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -808,6 +808,7 @@ std::optional FromTL( .id = data.vid().v, .slug = qs(data.vslug()), .title = qs(data.vtitle()), + .ownerAddress = qs(data.vowner_address().value_or_empty()), .ownerName = qs(data.vowner_name().value_or_empty()), .ownerId = (data.vowner_id() ? peerFromMTP(*data.vowner_id()) diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index aa83032a9..bc226f66f 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_badge.h" #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" +#include "main/main_app_config.h" #include "main/main_session.h" #include "mainwidget.h" #include "payments/payments_checkout_process.h" @@ -131,6 +132,23 @@ constexpr auto kRarityTooltipDuration = 3 * crl::time(1000); : tr::lng_premium_gift_duration_years; } +[[nodiscard]] object_ptr MakeMaybeMultilineTokenValue( + not_null table, + const QString &token, + Settings::CreditsEntryBoxStyleOverrides st) { + constexpr auto kOneLineCount = 24; + const auto oneLine = token.length() <= kOneLineCount; + return object_ptr( + table, + rpl::single( + Ui::Text::Wrapped({ token }, EntityType::Code, {})), + (oneLine + ? table->st().defaultValue + : st.tableValueMultiline + ? *st.tableValueMultiline + : st::giveawayGiftCodeValueMultiline)); +} + [[nodiscard]] object_ptr MakePeerTableValue( not_null table, std::shared_ptr show, @@ -1223,6 +1241,15 @@ void ResolveGiveawayInfo( crl::guard(controller, show)); } +QString TonAddressUrl( + not_null session, + const QString &address) { + const auto prefix = session->appConfig().get( + u"ton_blockchain_explorer_url"_q, + u"https://tonviewer.com/"_q); + return prefix + address; +} + void AddStarGiftTable( std::shared_ptr show, not_null container, @@ -1335,10 +1362,26 @@ void AddStarGiftTable( MakePeerWithStatusValue(table, show, ownerId, handleChange), st::giveawayGiftCodePeerMargin); } else if (unique) { - AddTableRow( - table, - tr::lng_gift_unique_owner(), - rpl::single(TextWithEntities{ unique->ownerName })); + if (!unique->ownerName.isEmpty()) { + AddTableRow( + table, + tr::lng_gift_unique_owner(), + rpl::single(TextWithEntities{ unique->ownerName })); + } else if (auto address = unique->ownerAddress; !address.isEmpty()) { + auto label = MakeMaybeMultilineTokenValue(table, address, st); + label->setClickHandlerFilter([=](const auto &...) { + TextUtilities::SetClipboardText( + TextForMimeData::Simple(address)); + show->showToast( + tr::lng_gift_unique_address_copied(tr::now)); + return false; + }); + AddTableRow( + table, + tr::lng_gift_unique_owner(), + std::move(label), + st::giveawayGiftCodeValueMargin); + } } else if (giftToChannel) { AddTableRow( table, @@ -1724,17 +1767,7 @@ void AddCreditsHistoryEntryTable( Ui::Text::WithEntities)); } if (!entry.id.isEmpty()) { - constexpr auto kOneLineCount = 24; - const auto oneLine = entry.id.length() <= kOneLineCount; - auto label = object_ptr( - table, - rpl::single( - Ui::Text::Wrapped({ entry.id }, EntityType::Code, {})), - (oneLine - ? table->st().defaultValue - : st.tableValueMultiline - ? *st.tableValueMultiline - : st::giveawayGiftCodeValueMultiline)); + auto label = MakeMaybeMultilineTokenValue(table, entry.id, st); label->setClickHandlerFilter([=](const auto &...) { TextUtilities::SetClipboardText( TextForMimeData::Simple(entry.id)); diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.h b/Telegram/SourceFiles/boxes/gift_premium_box.h index 54aad1b3d..ec3282e24 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.h +++ b/Telegram/SourceFiles/boxes/gift_premium_box.h @@ -25,6 +25,10 @@ struct GiveawayResults; struct SubscriptionEntry; } // namespace Data +namespace Main { +class Session; +} // namespace Main + namespace Settings { struct CreditsEntryBoxStyleOverrides; } // namespace Settings @@ -62,6 +66,10 @@ void ResolveGiveawayInfo( std::optional start, std::optional results); +[[nodiscard]] QString TonAddressUrl( + not_null session, + const QString &address); + void AddStarGiftTable( std::shared_ptr show, not_null container, diff --git a/Telegram/SourceFiles/data/data_star_gift.h b/Telegram/SourceFiles/data/data_star_gift.h index 90b3cc975..77bcc082d 100644 --- a/Telegram/SourceFiles/data/data_star_gift.h +++ b/Telegram/SourceFiles/data/data_star_gift.h @@ -40,6 +40,7 @@ struct UniqueGift { CollectibleId id = 0; QString slug; QString title; + QString ownerAddress; QString ownerName; PeerId ownerId = 0; int number = 0; 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 3321dab5b..0144f4691 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_premium_gift.h" #include "apiwrap.h" +#include "api/api_credits.h" // InputSavedStarGiftId #include "api/api_premium.h" #include "base/unixtime.h" #include "boxes/gift_premium_box.h" // ResolveGiftCode @@ -219,6 +220,9 @@ bool PremiumGift::buttonMinistars() { } ClickHandlerPtr PremiumGift::createViewLink() { + if (auto link = OpenStarGiftLink(_parent->data())) { + return link; + } const auto from = _gift->from(); const auto itemId = _parent->data()->fullId(); const auto peer = _parent->history()->peer; @@ -232,16 +236,7 @@ ClickHandlerPtr PremiumGift::createViewLink() { } const auto selfId = controller->session().userPeerId(); const auto sent = (from->id == selfId); - if (starGift()) { - const auto item = controller->session().data().message(itemId); - if (item) { - controller->show(Box( - Settings::StarGiftViewBox, - controller, - data, - item)); - } - } else if (creditsPrize()) { + if (creditsPrize()) { controller->show(Box( Settings::CreditsPrizeBox, controller, @@ -265,49 +260,6 @@ ClickHandlerPtr PremiumGift::createViewLink() { ResolveGiftCode(controller, data.slug, fromId, toId); } }; - - if (const auto upgradeTo = data.upgradeMsgId) { - const auto requesting = std::make_shared(); - return std::make_shared([=]( - ClickContext context) { - const auto my = context.other.value(); - const auto weak = my.sessionWindow; - const auto controller = weak.get(); - if (!controller || *requesting) { - return; - } - *requesting = true; - controller->session().api().request(MTPpayments_GetSavedStarGift( - MTP_vector( - 1, - MTP_inputSavedStarGiftUser(MTP_int(upgradeTo))) - )).done([=](const MTPpayments_SavedStarGifts &result) { - *requesting = false; - if (const auto window = weak.get()) { - const auto &data = result.data(); - window->session().data().processUsers(data.vusers()); - window->session().data().processChats(data.vchats()); - const auto self = window->session().user(); - const auto &list = data.vgifts().v; - if (list.empty()) { - showForWeakWindow(weak); - } else if (auto parsed = Api::FromTL(self, list[0])) { - window->show(Box( - Settings::SavedStarGiftBox, - window, - self, - *parsed)); - } - } - }).fail([=](const MTP::Error &error) { - *requesting = false; - if (const auto window = weak.get()) { - window->showToast(error.type()); - } - showForWeakWindow(weak); - }).send(); - }); - } return std::make_shared([=](ClickContext context) { showForWeakWindow( context.other.value().sessionWindow); @@ -447,4 +399,76 @@ void PremiumGift::ensureStickerCreated() const { } } +ClickHandlerPtr OpenStarGiftLink(not_null item) { + const auto media = item->media(); + const auto gift = media ? media->gift() : nullptr; + if (!gift || gift->type != Data::GiftType::StarGift) { + return nullptr; + } + const auto data = *gift; + const auto itemId = item->fullId(); + const auto openInsteadId = data.upgradeMsgId + ? Data::SavedStarGiftId::User(data.upgradeMsgId) + : (data.channel && data.channelSavedId) + ? Data::SavedStarGiftId::Chat(data.channel, data.channelSavedId) + : Data::SavedStarGiftId(); + const auto requesting = std::make_shared(); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + const auto weak = my.sessionWindow; + const auto controller = weak.get(); + if (!controller) { + return; + } + const auto quick = [=](not_null window) { + const auto item = window->session().data().message(itemId); + if (item) { + window->show(Box( + Settings::StarGiftViewBox, + window, + data, + item)); + } + }; + if (!openInsteadId) { + quick(controller); + return; + } else if (*requesting) { + return; + } + *requesting = true; + controller->session().api().request(MTPpayments_GetSavedStarGift( + MTP_vector( + 1, + Api::InputSavedStarGiftId(openInsteadId)) + )).done([=](const MTPpayments_SavedStarGifts &result) { + *requesting = false; + if (const auto window = weak.get()) { + const auto &data = result.data(); + window->session().data().processUsers(data.vusers()); + window->session().data().processChats(data.vchats()); + const auto owner = openInsteadId.chat() + ? openInsteadId.chat() + : window->session().user(); + const auto &list = data.vgifts().v; + if (list.empty()) { + quick(window); + } else if (auto parsed = Api::FromTL(owner, list[0])) { + window->show(Box( + Settings::SavedStarGiftBox, + window, + owner, + *parsed)); + } + } + }).fail([=](const MTP::Error &error) { + *requesting = false; + if (const auto window = weak.get()) { + window->showToast(error.type()); + quick(window); + } + }).send(); + }); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h index fcc503464..fe8cc312d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h @@ -68,4 +68,6 @@ private: }; +[[nodiscard]] ClickHandlerPtr OpenStarGiftLink(not_null item); + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp index 228ac5d20..8bd65cfd4 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_star_gift.h" #include "history/view/media/history_view_media_generic.h" +#include "history/view/media/history_view_premium_gift.h" #include "history/view/history_view_cursor_state.h" #include "history/view/history_view_element.h" #include "history/history.h" @@ -457,24 +458,7 @@ auto GenerateUniqueGiftMedia( gift->backdrop.textColor)); const auto itemId = parent->data()->fullId(); - auto link = std::make_shared([=]( - ClickContext context) { - const auto my = context.other.value(); - if (const auto controller = my.sessionWindow.get()) { - const auto owner = &controller->session().data(); - if (const auto item = owner->message(itemId)) { - if (const auto media = item->media()) { - if (const auto gift = media->gift()) { - controller->show(Box( - Settings::StarGiftViewBox, - controller, - *gift, - item)); - } - } - } - } - }); + auto link = OpenStarGiftLink(parent->data()); push(std::make_unique( tr::lng_sticker_premium_view(tr::now), st::chatUniqueButtonPadding, diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index e1b7ced9d..15ea3aac0 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -1604,6 +1604,20 @@ void GenericCreditsEntryBox( toggleVisibility(!e.savedToProfile); return false; }); + } else if (uniqueGift && !uniqueGift->ownerAddress.isEmpty()) { + const auto label = box->addRow( + object_ptr( + box, + tr::lng_gift_in_blockchain( + lt_link, + tr::lng_gift_in_blockchain_link() | Ui::Text::ToLink(), + Ui::Text::WithEntities), + st::creditsBoxAboutDivider)); + label->setClickHandlerFilter([=](const auto &...) { + UrlClickHandler::Open( + TonAddressUrl(session, uniqueGift->ownerAddress)); + return false; + }); } if (s) { const auto user = peer ? peer->asUser() : nullptr;