From cd8e944751e5a2384ec174bca55af34778dc0a98 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 17 Jun 2025 10:03:33 +0300 Subject: [PATCH] Added recent gifts to section of shared media from info profile. --- Telegram/CMakeLists.txt | 2 + .../components/recent_shared_media_gifts.cpp | 79 +++++++++++++++ .../components/recent_shared_media_gifts.h | 38 ++++++++ .../info/media/info_media_buttons.cpp | 97 +++++++++++++++++-- Telegram/SourceFiles/main/main_session.cpp | 2 + Telegram/SourceFiles/main/main_session.h | 5 + 6 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 Telegram/SourceFiles/data/components/recent_shared_media_gifts.cpp create mode 100644 Telegram/SourceFiles/data/components/recent_shared_media_gifts.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a27e737f1e..f07a2e4e7f 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -511,6 +511,8 @@ PRIVATE data/components/promo_suggestions.h data/components/recent_peers.cpp data/components/recent_peers.h + data/components/recent_shared_media_gifts.cpp + data/components/recent_shared_media_gifts.h data/components/scheduled_messages.cpp data/components/scheduled_messages.h data/components/sponsored_messages.cpp diff --git a/Telegram/SourceFiles/data/components/recent_shared_media_gifts.cpp b/Telegram/SourceFiles/data/components/recent_shared_media_gifts.cpp new file mode 100644 index 0000000000..a23b09110b --- /dev/null +++ b/Telegram/SourceFiles/data/components/recent_shared_media_gifts.cpp @@ -0,0 +1,79 @@ +/* +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 +*/ +#include "data/components/recent_shared_media_gifts.h" + +#include "api/api_premium.h" +#include "apiwrap.h" +#include "data/data_document.h" +#include "data/data_peer.h" +#include "data/data_session.h" +#include "main/main_session.h" + +namespace Data { +namespace { + +constexpr auto kReloadThreshold = 60 * crl::time(1000); +constexpr auto kMaxGifts = 3; + +} // namespace + +RecentSharedMediaGifts::RecentSharedMediaGifts( + not_null session) +: _session(session) { +} + +RecentSharedMediaGifts::~RecentSharedMediaGifts() = default; + +void RecentSharedMediaGifts::request( + not_null peer, + Fn)> done) { + const auto it = _recent.find(peer->id); + if (it != _recent.end()) { + auto &entry = it->second; + if (entry.lastRequestTime + && entry.lastRequestTime + kReloadThreshold > crl::now()) { + done(std::vector(entry.ids.begin(), entry.ids.end())); + return; + } + if (entry.requestId) { + peer->session().api().request(entry.requestId).cancel(); + } + } + + _recent[peer->id].requestId = peer->session().api().request( + MTPpayments_GetSavedStarGifts( + MTP_flags(0), + peer->input, + MTP_string(QString()), + MTP_int(kMaxGifts) + )).done([=](const MTPpayments_SavedStarGifts &result) { + const auto &data = result.data(); + const auto owner = &peer->owner(); + owner->processUsers(data.vusers()); + owner->processChats(data.vchats()); + auto &entry = _recent[peer->id]; + entry.lastRequestTime = crl::now(); + entry.requestId = 0; + + auto conter = 0; + for (const auto &gift : data.vgifts().v) { + if (auto parsed = Api::FromTL(peer, gift)) { + entry.ids.push_front(parsed->info.document->id); + if (entry.ids.size() > kMaxGifts) { + entry.ids.pop_back(); + } + if (++conter >= kMaxGifts) { + break; + } + } + } + done(std::vector(entry.ids.begin(), entry.ids.end())); + }).send(); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/components/recent_shared_media_gifts.h b/Telegram/SourceFiles/data/components/recent_shared_media_gifts.h new file mode 100644 index 0000000000..f3d81fbda4 --- /dev/null +++ b/Telegram/SourceFiles/data/components/recent_shared_media_gifts.h @@ -0,0 +1,38 @@ +/* +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 + +namespace Main { +class Session; +} // namespace Main + +namespace Data { + +class RecentSharedMediaGifts final { +public: + explicit RecentSharedMediaGifts(not_null session); + ~RecentSharedMediaGifts(); + + void request( + not_null peer, + Fn)> done); + +private: + struct Entry { + std::deque ids; + crl::time lastRequestTime = 0; + mtpRequestId requestId = 0; + }; + + const not_null _session; + + base::flat_map _recent; + +}; + +} // namespace Data diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.cpp b/Telegram/SourceFiles/info/media/info_media_buttons.cpp index 5a2b78e952..4757b24b56 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.cpp +++ b/Telegram/SourceFiles/info/media/info_media_buttons.cpp @@ -10,18 +10,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "base/qt/qt_key_modifiers.h" #include "core/application.h" +#include "core/ui_integration.h" +#include "data/components/recent_shared_media_gifts.h" #include "data/data_channel.h" #include "data/data_saved_messages.h" #include "data/data_saved_sublist.h" #include "data/data_session.h" #include "data/data_stories_ids.h" #include "data/data_user.h" -#include "history/view/history_view_chat_section.h" +#include "data/stickers/data_custom_emoji.h" #include "history/history.h" +#include "history/view/history_view_chat_section.h" #include "info/info_controller.h" #include "info/info_memento.h" #include "info/profile/info_profile_values.h" #include "info/stories/info_stories_widget.h" +#include "main/main_session.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "ui/wrap/slide_wrap.h" @@ -293,14 +298,86 @@ not_null AddPeerGiftsButton( not_null navigation, not_null peer, Ui::MultiSlideTracker &tracker) { - auto result = AddCountedButton( - parent, - Profile::PeerGiftsCountValue(peer), - [](int count) { - return tr::lng_profile_peer_gifts(tr::now, lt_count, count); - }, - tracker)->entity(); - result->addClickHandler([=] { + + auto count = Profile::PeerGiftsCountValue(peer); + auto textFromCount = [](int count) { + return tr::lng_profile_peer_gifts(tr::now, lt_count, count); + }; + + using namespace ::Settings; + auto forked = std::move(count) + | start_spawning(parent->lifetime()); + auto text = rpl::duplicate( + forked + ) | rpl::map([textFromCount](int count) { + return (count > 0) + ? textFromCount(count) + : QString(); + }); + + struct State final { + std::optional api; + std::vector> emojiList; + rpl::event_stream<> textRefreshed; + QPointer button; + }; + const auto state = parent->lifetime().make_state(); + + const auto refresh = [=] { + if (state->button) { + state->button->update(); + } + }; + + state->api.emplace(&navigation->session().mtp()); + + auto customs = state->textRefreshed.events( + ) | rpl::map([=]() -> TextWithEntities { + auto result = TextWithEntities(); + for (const auto &custom : state->emojiList) { + result.append(Ui::Text::SingleCustomEmoji(custom->entityData())); + } + return result; + }); + + const auto wrap = parent->add( + object_ptr>( + parent, + object_ptr( + parent, + rpl::combine( + std::move(text), + std::move(customs) + ) | rpl::map([=](QString text, TextWithEntities customs) { + return TextWithEntities() + .append(std::move(text)) + .append(QChar(' ')) + .append(std::move(customs)); + }), + st::infoSharedMediaButton, + Core::TextContext({ + .session = &navigation->session(), + .details = { .session = &navigation->session() }, + .repaint = refresh, + .customEmojiLoopLimit = 1, + })))); + wrap->setDuration(st::infoSlideDuration); + wrap->toggleOn(rpl::duplicate(forked) | rpl::map(rpl::mappers::_1 > 0)); + tracker.track(wrap); + + navigation->session().recentSharedGifts().request(peer, [=]( + std::vector ids) { + state->emojiList.clear(); + for (const auto &id : ids) { + state->emojiList.push_back( + peer->owner().customEmojiManager().create(id, refresh)); + } + state->textRefreshed.fire({}); + }); + + state->button = wrap->entity(); + + wrap->entity()->addClickHandler([=] { if (navigation->showFrozenError()) { return; } @@ -309,7 +386,7 @@ not_null AddPeerGiftsButton( peer, Section::Type::PeerGifts)); }); - return result; + return wrap->entity(); } } // namespace Info::Media diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 0df874fb2f..4b90f06dcd 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/components/location_pickers.h" #include "data/components/promo_suggestions.h" #include "data/components/recent_peers.h" +#include "data/components/recent_shared_media_gifts.h" #include "data/components/scheduled_messages.h" #include "data/components/sponsored_messages.h" #include "data/components/top_peers.h" @@ -110,6 +111,7 @@ Session::Session( , _sendAsPeers(std::make_unique(this)) , _attachWebView(std::make_unique(this)) , _recentPeers(std::make_unique(this)) +, _recentSharedGifts(std::make_unique(this)) , _scheduledMessages(std::make_unique(this)) , _sponsoredMessages(std::make_unique(this)) , _topPeers(std::make_unique(this, Data::TopPeerType::Chat)) diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 6d5eaf38f7..d671d46e08 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -33,6 +33,7 @@ namespace Data { class Session; class Changes; class RecentPeers; +class RecentSharedMediaGifts; class ScheduledMessages; class SponsoredMessages; class TopPeers; @@ -133,6 +134,9 @@ public: [[nodiscard]] Data::RecentPeers &recentPeers() const { return *_recentPeers; } + [[nodiscard]] Data::RecentSharedMediaGifts &recentSharedGifts() const { + return *_recentSharedGifts; + } [[nodiscard]] Data::SponsoredMessages &sponsoredMessages() const { return *_sponsoredMessages; } @@ -287,6 +291,7 @@ private: const std::unique_ptr _sendAsPeers; const std::unique_ptr _attachWebView; const std::unique_ptr _recentPeers; + const std::unique_ptr _recentSharedGifts; const std::unique_ptr _scheduledMessages; const std::unique_ptr _sponsoredMessages; const std::unique_ptr _topPeers;