Partially implement viewing channel gifts.

This commit is contained in:
John Preston 2025-01-10 18:06:11 +04:00
parent 2fd174ab9c
commit 81001e04e9
15 changed files with 81 additions and 56 deletions

View file

@ -834,7 +834,7 @@ std::optional<Data::StarGift> FromTL(
} }
std::optional<Data::UserStarGift> FromTL( std::optional<Data::UserStarGift> FromTL(
not_null<UserData*> to, not_null<PeerData*> to,
const MTPuserStarGift &gift) { const MTPuserStarGift &gift) {
const auto session = &to->session(); const auto session = &to->session();
const auto &data = gift.data(); const auto &data = gift.data();

View file

@ -260,7 +260,7 @@ enum class RequirePremiumState {
not_null<Main::Session*> session, not_null<Main::Session*> session,
const MTPstarGift &gift); const MTPstarGift &gift);
[[nodiscard]] std::optional<Data::UserStarGift> FromTL( [[nodiscard]] std::optional<Data::UserStarGift> FromTL(
not_null<UserData*> to, not_null<PeerData*> to,
const MTPuserStarGift &gift); const MTPuserStarGift &gift);
[[nodiscard]] Data::UniqueGiftModel FromTL( [[nodiscard]] Data::UniqueGiftModel FromTL(

View file

@ -714,6 +714,10 @@ bool ChannelData::canRestrictParticipant(
return adminRights() & AdminRight::BanUsers; return adminRights() & AdminRight::BanUsers;
} }
bool ChannelData::canManageGifts() const {
return amCreator(); // todo channel gifts
}
void ChannelData::setBotVerifyDetails(Ui::BotVerifyDetails details) { void ChannelData::setBotVerifyDetails(Ui::BotVerifyDetails details) {
if (!details) { if (!details) {
if (_botVerifyDetails) { if (_botVerifyDetails) {
@ -859,6 +863,17 @@ void ChannelData::growSlowmodeLastMessage(TimeId when) {
session().changes().peerUpdated(this, UpdateFlag::Slowmode); session().changes().peerUpdated(this, UpdateFlag::Slowmode);
} }
int ChannelData::peerGiftsCount() const {
return _peerGiftsCount;
}
void ChannelData::setPeerGiftsCount(int count) {
if (_peerGiftsCount != count) {
_peerGiftsCount = count;
session().changes().peerUpdated(this, UpdateFlag::PeerGifts);
}
}
int ChannelData::boostsApplied() const { int ChannelData::boostsApplied() const {
if (const auto info = mgInfo.get()) { if (const auto info = mgInfo.get()) {
return info->boostsApplied; return info->boostsApplied;

View file

@ -375,6 +375,7 @@ public:
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const; [[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canRestrictParticipant( [[nodiscard]] bool canRestrictParticipant(
not_null<PeerData*> participant) const; not_null<PeerData*> participant) const;
[[nodiscard]] bool canManageGifts() const;
void setBotVerifyDetails(Ui::BotVerifyDetails details); void setBotVerifyDetails(Ui::BotVerifyDetails details);
void setBotVerifyDetailsIcon(DocumentId iconId); void setBotVerifyDetailsIcon(DocumentId iconId);
@ -452,6 +453,9 @@ public:
[[nodiscard]] TimeId slowmodeLastMessage() const; [[nodiscard]] TimeId slowmodeLastMessage() const;
void growSlowmodeLastMessage(TimeId when); void growSlowmodeLastMessage(TimeId when);
[[nodiscard]] int peerGiftsCount() const;
void setPeerGiftsCount(int count);
[[nodiscard]] int boostsApplied() const; [[nodiscard]] int boostsApplied() const;
[[nodiscard]] int boostsUnrestrict() const; [[nodiscard]] int boostsUnrestrict() const;
[[nodiscard]] bool unrestrictedByBoosts() const; [[nodiscard]] bool unrestrictedByBoosts() const;
@ -522,6 +526,7 @@ private:
std::vector<Data::UnavailableReason> &&reasons) override; std::vector<Data::UnavailableReason> &&reasons) override;
Flags _flags = ChannelDataFlags(Flag::Forbidden); Flags _flags = ChannelDataFlags(Flag::Forbidden);
int _peerGiftsCount = 0;
PtsWaiter _ptsWaiter; PtsWaiter _ptsWaiter;

View file

@ -1532,6 +1532,15 @@ void PeerData::setStoriesState(StoriesState state) {
} }
} }
int PeerData::peerGiftsCount() const {
if (const auto user = asUser()) {
return user->peerGiftsCount();
} else if (const auto channel = asChannel()) {
return channel->peerGiftsCount();
}
return 0;
}
void PeerData::setIsBlocked(bool is) { void PeerData::setIsBlocked(bool is) {
const auto status = is const auto status = is
? BlockStatus::Blocked ? BlockStatus::Blocked

View file

@ -486,6 +486,8 @@ public:
[[nodiscard]] bool hasUnreadStories() const; [[nodiscard]] bool hasUnreadStories() const;
void setStoriesState(StoriesState state); void setStoriesState(StoriesState state);
[[nodiscard]] int peerGiftsCount() const;
const PeerId id; const PeerId id;
MTPinputPeer input = MTP_inputPeerEmpty(); MTPinputPeer input = MTP_inputPeerEmpty();

View file

@ -177,7 +177,7 @@ std::shared_ptr<ContentMemento> Memento::DefaultContent(
case Section::Type::RequestsList: case Section::Type::RequestsList:
return std::make_shared<RequestsList::Memento>(peer); return std::make_shared<RequestsList::Memento>(peer);
case Section::Type::PeerGifts: case Section::Type::PeerGifts:
return std::make_shared<PeerGifts::Memento>(peer->asUser()); return std::make_shared<PeerGifts::Memento>(peer);
case Section::Type::SavedSublists: case Section::Type::SavedSublists:
return std::make_shared<Saved::SublistsMemento>(&peer->session()); return std::make_shared<Saved::SublistsMemento>(&peer->session());
case Section::Type::Members: case Section::Type::Members:

View file

@ -205,11 +205,11 @@ inline auto AddSavedSublistButton(
inline auto AddPeerGiftsButton( inline auto AddPeerGiftsButton(
Ui::VerticalLayout *parent, Ui::VerticalLayout *parent,
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<UserData*> user, not_null<PeerData*> peer,
Ui::MultiSlideTracker &tracker) { Ui::MultiSlideTracker &tracker) {
auto result = AddCountedButton( auto result = AddCountedButton(
parent, parent,
Profile::PeerGiftsCountValue(user), Profile::PeerGiftsCountValue(peer),
[](int count) { [](int count) {
return tr::lng_profile_peer_gifts(tr::now, lt_count, count); return tr::lng_profile_peer_gifts(tr::now, lt_count, count);
}, },
@ -217,7 +217,7 @@ inline auto AddPeerGiftsButton(
result->addClickHandler([=] { result->addClickHandler([=] {
navigation->showSection( navigation->showSection(
std::make_shared<Info::Memento>( std::make_shared<Info::Memento>(
user, peer,
Section::Type::PeerGifts)); Section::Type::PeerGifts));
}); });
return result; return result;

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/peer_gifts/info_peer_gifts_widget.h" #include "info/peer_gifts/info_peer_gifts_widget.h"
#include "api/api_premium.h" #include "api/api_premium.h"
#include "data/data_channel.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "info/peer_gifts/info_peer_gifts_common.h" #include "info/peer_gifts/info_peer_gifts_common.h"
@ -32,7 +33,7 @@ constexpr auto kPreloadPages = 2;
constexpr auto kPerPage = 50; constexpr auto kPerPage = 50;
[[nodiscard]] GiftDescriptor DescriptorForGift( [[nodiscard]] GiftDescriptor DescriptorForGift(
not_null<UserData*> to, not_null<PeerData*> to,
const Data::UserStarGift &gift) { const Data::UserStarGift &gift) {
return GiftTypeStars{ return GiftTypeStars{
.info = gift.info, .info = gift.info,
@ -52,10 +53,10 @@ public:
InnerWidget( InnerWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user); not_null<PeerData*> peer);
[[nodiscard]] not_null<UserData*> user() const { [[nodiscard]] not_null<PeerData*> peer() const {
return _user; return _peer;
} }
void saveState(not_null<Memento*> memento); void saveState(not_null<Memento*> memento);
@ -88,7 +89,7 @@ private:
Delegate _delegate; Delegate _delegate;
not_null<Controller*> _controller; not_null<Controller*> _controller;
std::unique_ptr<Ui::FlatLabel> _about; std::unique_ptr<Ui::FlatLabel> _about;
const not_null<UserData*> _user; const not_null<PeerData*> _peer;
std::vector<Entry> _entries; std::vector<Entry> _entries;
int _totalCount = 0; int _totalCount = 0;
@ -113,32 +114,33 @@ private:
InnerWidget::InnerWidget( InnerWidget::InnerWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user) not_null<PeerData*> peer)
: BoxContentDivider(parent) : BoxContentDivider(parent)
, _window(controller->parentController()) , _window(controller->parentController())
, _delegate(_window, GiftButtonMode::Minimal) , _delegate(_window, GiftButtonMode::Minimal)
, _controller(controller) , _controller(controller)
, _about(std::make_unique<Ui::FlatLabel>( , _about(std::make_unique<Ui::FlatLabel>(
this, this,
(user->isSelf() (peer->isSelf()
? tr::lng_peer_gifts_about_mine(Ui::Text::RichLangValue) ? tr::lng_peer_gifts_about_mine(Ui::Text::RichLangValue)
: tr::lng_peer_gifts_about( : tr::lng_peer_gifts_about(
lt_user, lt_user,
rpl::single(Ui::Text::Bold(user->shortName())), rpl::single(Ui::Text::Bold(peer->shortName())),
Ui::Text::RichLangValue)), Ui::Text::RichLangValue)),
st::giftListAbout)) st::giftListAbout))
, _user(user) , _peer(peer)
, _totalCount(_user->peerGiftsCount()) , _totalCount(_peer->peerGiftsCount())
, _api(&_user->session().mtp()) { , _api(&_peer->session().mtp()) {
_singleMin = _delegate.buttonSize(); _singleMin = _delegate.buttonSize();
if (user->isSelf()) { const auto channel = peer->asBroadcast();
if (peer->isSelf() || (channel && channel->canManageGifts())) {
subscribeToUpdates(); subscribeToUpdates();
} }
} }
void InnerWidget::subscribeToUpdates() { void InnerWidget::subscribeToUpdates() {
_user->owner().giftUpdates( _peer->owner().giftUpdates(
) | rpl::start_with_next([=](const Data::GiftUpdate &update) { ) | rpl::start_with_next([=](const Data::GiftUpdate &update) {
const auto itemId = [](const Entry &entry) { const auto itemId = [](const Entry &entry) {
return FullMsgId(entry.gift.fromId, entry.gift.messageId); return FullMsgId(entry.gift.fromId, entry.gift.messageId);
@ -202,11 +204,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
} }
void InnerWidget::loadMore() { void InnerWidget::loadMore() {
if (_allLoaded || _loadMoreRequestId) { if (_allLoaded || _loadMoreRequestId || !_peer->isUser()) {
return; return; // todo channel gifts
} }
_loadMoreRequestId = _api.request(MTPpayments_GetUserStarGifts( _loadMoreRequestId = _api.request(MTPpayments_GetUserStarGifts(
_user->inputUser, _peer->asUser()->inputUser,
MTP_string(_offset), MTP_string(_offset),
MTP_int(kPerPage) MTP_int(kPerPage)
)).done([=](const MTPpayments_UserStarGifts &result) { )).done([=](const MTPpayments_UserStarGifts &result) {
@ -219,13 +221,13 @@ void InnerWidget::loadMore() {
} }
_totalCount = data.vcount().v; _totalCount = data.vcount().v;
const auto owner = &_user->owner(); const auto owner = &_peer->owner();
owner->processUsers(data.vusers()); owner->processUsers(data.vusers());
_entries.reserve(_entries.size() + data.vgifts().v.size()); _entries.reserve(_entries.size() + data.vgifts().v.size());
for (const auto &gift : data.vgifts().v) { for (const auto &gift : data.vgifts().v) {
if (auto parsed = Api::FromTL(_user, gift)) { if (auto parsed = Api::FromTL(_peer, gift)) {
auto descriptor = DescriptorForGift(_user, *parsed); auto descriptor = DescriptorForGift(_peer, *parsed);
_entries.push_back({ _entries.push_back({
.gift = std::move(*parsed), .gift = std::move(*parsed),
.descriptor = std::move(descriptor), .descriptor = std::move(descriptor),
@ -327,7 +329,7 @@ void InnerWidget::showGift(int index) {
_window->show(Box( _window->show(Box(
::Settings::UserStarGiftBox, ::Settings::UserStarGiftBox,
_window, _window,
_user, _peer,
_entries[index].gift)); _entries[index].gift));
} }
@ -373,23 +375,19 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
} }
} }
Memento::Memento(not_null<UserData*> user) Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(user, nullptr, PeerId()) { : ContentMemento(peer, nullptr, PeerId()) {
} }
Section Memento::section() const { Section Memento::section() const {
return Section(Section::Type::PeerGifts); return Section(Section::Type::PeerGifts);
} }
not_null<UserData*> Memento::user() const {
return peer()->asUser();
}
object_ptr<ContentWidget> Memento::createWidget( object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller, not_null<Controller*> controller,
const QRect &geometry) { const QRect &geometry) {
auto result = object_ptr<Widget>(parent, controller, user()); auto result = object_ptr<Widget>(parent, controller, peer());
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
return result; return result;
} }
@ -407,20 +405,20 @@ Memento::~Memento() = default;
Widget::Widget( Widget::Widget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user) not_null<PeerData*> peer)
: ContentWidget(parent, controller) { : ContentWidget(parent, controller) {
_inner = setInnerWidget(object_ptr<InnerWidget>( _inner = setInnerWidget(object_ptr<InnerWidget>(
this, this,
controller, controller,
user)); peer));
} }
rpl::producer<QString> Widget::title() { rpl::producer<QString> Widget::title() {
return tr::lng_peer_gifts_title(); return tr::lng_peer_gifts_title();
} }
not_null<UserData*> Widget::user() const { not_null<PeerData*> Widget::peer() const {
return _inner->user(); return _inner->peer();
} }
bool Widget::showInternal(not_null<ContentMemento*> memento) { bool Widget::showInternal(not_null<ContentMemento*> memento) {
@ -428,7 +426,7 @@ bool Widget::showInternal(not_null<ContentMemento*> memento) {
return false; return false;
} }
if (auto similarMemento = dynamic_cast<Memento*>(memento.get())) { if (auto similarMemento = dynamic_cast<Memento*>(memento.get())) {
if (similarMemento->user() == user()) { if (similarMemento->peer() == peer()) {
restoreState(similarMemento); restoreState(similarMemento);
return true; return true;
} }
@ -445,7 +443,7 @@ void Widget::setInternalState(
} }
std::shared_ptr<ContentMemento> Widget::doCreateMemento() { std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
auto result = std::make_shared<Memento>(user()); auto result = std::make_shared<Memento>(peer());
saveState(result.get()); saveState(result.get());
return result; return result;
} }

View file

@ -24,7 +24,7 @@ class InnerWidget;
class Memento final : public ContentMemento { class Memento final : public ContentMemento {
public: public:
explicit Memento(not_null<UserData*> user); explicit Memento(not_null<PeerData*> peer);
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
@ -33,8 +33,6 @@ public:
Section section() const override; Section section() const override;
[[nodiscard]] not_null<UserData*> user() const;
void setListState(std::unique_ptr<ListState> state); void setListState(std::unique_ptr<ListState> state);
std::unique_ptr<ListState> listState(); std::unique_ptr<ListState> listState();
@ -50,9 +48,9 @@ public:
Widget( Widget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user); not_null<PeerData*> peer);
[[nodiscard]] not_null<UserData*> user() const; [[nodiscard]] not_null<PeerData*> peer() const;
bool showInternal( bool showInternal(
not_null<ContentMemento*> memento) override; not_null<ContentMemento*> memento) override;

View file

@ -221,12 +221,12 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
st::infoSharedMediaButtonIconPosition); st::infoSharedMediaButtonIconPosition);
}; };
auto addPeerGiftsButton = [&]( auto addPeerGiftsButton = [&](
not_null<UserData*> user, not_null<PeerData*> peer,
const style::icon &icon) { const style::icon &icon) {
auto result = Media::AddPeerGiftsButton( auto result = Media::AddPeerGiftsButton(
content, content,
_controller, _controller,
user, peer,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(
result, result,
@ -236,9 +236,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
if (!_topic) { if (!_topic) {
addStoriesButton(_peer, st::infoIconMediaStories); addStoriesButton(_peer, st::infoIconMediaStories);
if (const auto user = _peer->asUser()) { addPeerGiftsButton(_peer, st::infoIconMediaGifts);
addPeerGiftsButton(user, st::infoIconMediaGifts);
}
addSavedSublistButton(_peer, st::infoIconMediaSaved); addSavedSublistButton(_peer, st::infoIconMediaSaved);
} }
addMediaButton(MediaType::Photo, st::infoIconMediaPhoto); addMediaButton(MediaType::Photo, st::infoIconMediaPhoto);

View file

@ -595,12 +595,12 @@ rpl::producer<int> SavedSublistCountValue(
return sublist->fullCountValue(); return sublist->fullCountValue();
} }
rpl::producer<int> PeerGiftsCountValue(not_null<UserData*> user) { rpl::producer<int> PeerGiftsCountValue(not_null<PeerData*> peer) {
return user->session().changes().peerFlagsValue( return peer->session().changes().peerFlagsValue(
user, peer,
UpdateFlag::PeerGifts UpdateFlag::PeerGifts
) | rpl::map([=] { ) | rpl::map([=] {
return user->peerGiftsCount(); return peer->peerGiftsCount();
}); });
} }

View file

@ -122,7 +122,7 @@ struct LinkWithUrl {
[[nodiscard]] rpl::producer<int> SavedSublistCountValue( [[nodiscard]] rpl::producer<int> SavedSublistCountValue(
not_null<PeerData*> peer); not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<int> PeerGiftsCountValue( [[nodiscard]] rpl::producer<int> PeerGiftsCountValue(
not_null<UserData*> user); not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<bool> CanAddMemberValue( [[nodiscard]] rpl::producer<bool> CanAddMemberValue(
not_null<PeerData*> peer); not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<int> FullReactionsCountValue( [[nodiscard]] rpl::producer<int> FullReactionsCountValue(

View file

@ -1748,7 +1748,7 @@ void GlobalStarGiftBox(
void UserStarGiftBox( void UserStarGiftBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<UserData*> owner, not_null<PeerData*> owner,
const Data::UserStarGift &data) { const Data::UserStarGift &data) {
Settings::ReceiptCreditsBox( Settings::ReceiptCreditsBox(
box, box,

View file

@ -138,7 +138,7 @@ void GlobalStarGiftBox(
void UserStarGiftBox( void UserStarGiftBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<UserData*> owner, not_null<PeerData*> owner,
const Data::UserStarGift &data); const Data::UserStarGift &data);
void StarGiftViewBox( void StarGiftViewBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,