Added recent gifts to section of shared media from info profile.

This commit is contained in:
23rd 2025-06-17 10:03:33 +03:00
parent 66e05594f6
commit cd8e944751
6 changed files with 213 additions and 10 deletions

View file

@ -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

View file

@ -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<Main::Session*> session)
: _session(session) {
}
RecentSharedMediaGifts::~RecentSharedMediaGifts() = default;
void RecentSharedMediaGifts::request(
not_null<PeerData*> peer,
Fn<void(std::vector<DocumentId>)> 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<DocumentId>(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<DocumentId>(entry.ids.begin(), entry.ids.end()));
}).send();
}
} // namespace Data

View file

@ -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<Main::Session*> session);
~RecentSharedMediaGifts();
void request(
not_null<PeerData*> peer,
Fn<void(std::vector<DocumentId>)> done);
private:
struct Entry {
std::deque<DocumentId> ids;
crl::time lastRequestTime = 0;
mtpRequestId requestId = 0;
};
const not_null<Main::Session*> _session;
base::flat_map<PeerId, Entry> _recent;
};
} // namespace Data

View file

@ -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<Ui::SettingsButton*> AddPeerGiftsButton(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> 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<MTP::Sender> api;
std::vector<std::unique_ptr<Ui::Text::CustomEmoji>> emojiList;
rpl::event_stream<> textRefreshed;
QPointer<Ui::SettingsButton> button;
};
const auto state = parent->lifetime().make_state<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<Ui::SlideWrap<Ui::SettingsButton>>(
parent,
object_ptr<Ui::SettingsButton>(
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<DocumentId> 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<Ui::SettingsButton*> AddPeerGiftsButton(
peer,
Section::Type::PeerGifts));
});
return result;
return wrap->entity();
}
} // namespace Info::Media

View file

@ -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<SendAsPeers>(this))
, _attachWebView(std::make_unique<InlineBots::AttachWebView>(this))
, _recentPeers(std::make_unique<Data::RecentPeers>(this))
, _recentSharedGifts(std::make_unique<Data::RecentSharedMediaGifts>(this))
, _scheduledMessages(std::make_unique<Data::ScheduledMessages>(this))
, _sponsoredMessages(std::make_unique<Data::SponsoredMessages>(this))
, _topPeers(std::make_unique<Data::TopPeers>(this, Data::TopPeerType::Chat))

View file

@ -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> _sendAsPeers;
const std::unique_ptr<InlineBots::AttachWebView> _attachWebView;
const std::unique_ptr<Data::RecentPeers> _recentPeers;
const std::unique_ptr<Data::RecentSharedMediaGifts> _recentSharedGifts;
const std::unique_ptr<Data::ScheduledMessages> _scheduledMessages;
const std::unique_ptr<Data::SponsoredMessages> _sponsoredMessages;
const std::unique_ptr<Data::TopPeers> _topPeers;