2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-22 10:17:10 +00:00

Support collection links.

This commit is contained in:
John Preston 2025-07-30 14:03:46 +04:00
parent 170544f68d
commit 79650cf318
23 changed files with 167 additions and 39 deletions

View File

@ -3773,6 +3773,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_gift_collection_empty_text" = "Add some of your gifts to this collection."; "lng_gift_collection_empty_text" = "Add some of your gifts to this collection.";
"lng_gift_collection_all" = "All Gifts"; "lng_gift_collection_all" = "All Gifts";
"lng_gift_collection_add_title" = "Add Gifts"; "lng_gift_collection_add_title" = "Add Gifts";
"lng_gift_collection_share" = "Share Collection";
"lng_gift_collection_edit" = "Edit Name"; "lng_gift_collection_edit" = "Edit Name";
"lng_gift_collection_limit_title" = "Limit Reached"; "lng_gift_collection_limit_title" = "Limit Reached";
"lng_gift_collection_limit_text" = "Please remove one of the existing collections to add a new one."; "lng_gift_collection_limit_text" = "Please remove one of the existing collections to add a new one.";
@ -6267,6 +6268,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_view_button_collectible" = "View collectible"; "lng_view_button_collectible" = "View collectible";
"lng_view_button_call" = "Join call"; "lng_view_button_call" = "Join call";
"lng_view_button_storyalbum" = "View Album"; "lng_view_button_storyalbum" = "View Album";
"lng_view_button_collection" = "View Collection";
"lng_sponsored_hide_ads" = "Hide"; "lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?"; "lng_sponsored_title" = "What are sponsored messages?";

View File

@ -635,6 +635,8 @@ bool ResolveUsernameOrPhone(
const auto storyId = storyParam.toInt(); const auto storyId = storyParam.toInt();
const auto storyAlbumParam = params.value(u"album"_q); const auto storyAlbumParam = params.value(u"album"_q);
const auto storyAlbumId = storyAlbumParam.toInt(); const auto storyAlbumId = storyAlbumParam.toInt();
const auto giftCollectionParam = params.value(u"collection"_q);
const auto giftCollectionId = giftCollectionParam.toInt();
const auto appname = webChannelPreviewLink ? QString() : appnameParam; const auto appname = webChannelPreviewLink ? QString() : appnameParam;
const auto commentParam = params.value(u"comment"_q); const auto commentParam = params.value(u"comment"_q);
const auto commentId = commentParam.toInt(); const auto commentId = commentParam.toInt();
@ -662,6 +664,7 @@ bool ResolveUsernameOrPhone(
.messageId = post, .messageId = post,
.storyId = storyId, .storyId = storyId,
.storyAlbumId = storyAlbumId, .storyAlbumId = storyAlbumId,
.giftCollectionId = giftCollectionId,
.videoTimestamp = (!videot.isEmpty() .videoTimestamp = (!videot.isEmpty()
? ParseVideoTimestamp(videot) ? ParseVideoTimestamp(videot)
: std::optional<TimeId>()), : std::optional<TimeId>()),
@ -1847,6 +1850,7 @@ QString TryConvertUrlToLocal(QString url) {
"/\\d+/?(\\?|$)|" "/\\d+/?(\\?|$)|"
"/s/\\d+/?(\\?|$)|" "/s/\\d+/?(\\?|$)|"
"/a/\\d+/?(\\?|$)|" "/a/\\d+/?(\\?|$)|"
"/c/\\d+/?(\\?|$)|"
"/\\d+/\\d+/?(\\?|$)" "/\\d+/\\d+/?(\\?|$)"
")"_q, query, matchOptions)) { ")"_q, query, matchOptions)) {
const auto domain = usernameMatch->captured(1); const auto domain = usernameMatch->captured(1);
@ -1869,8 +1873,10 @@ QString TryConvertUrlToLocal(QString url) {
added = u"&post="_q + postMatch->captured(1); added = u"&post="_q + postMatch->captured(1);
} else if (const auto storyMatch = regex_match(u"^/s/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { } else if (const auto storyMatch = regex_match(u"^/s/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
added = u"&story="_q + storyMatch->captured(1); added = u"&story="_q + storyMatch->captured(1);
} else if (const auto storyMatch = regex_match(u"^/a/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { } else if (const auto albumMatch = regex_match(u"^/a/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
added = u"&album="_q + storyMatch->captured(1); added = u"&album="_q + albumMatch->captured(1);
} else if (const auto collectionMatch = regex_match(u"^/c/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
added = u"&collection="_q + collectionMatch->captured(1);
} else if (const auto appNameMatch = regex_match(u"^/([a-zA-Z0-9\\.\\_\\-]+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { } else if (const auto appNameMatch = regex_match(u"^/([a-zA-Z0-9\\.\\_\\-]+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) {
added = u"&appname="_q + appNameMatch->captured(1); added = u"&appname="_q + appNameMatch->captured(1);
} }

View File

@ -61,6 +61,8 @@ struct FileReferenceAccumulator {
push(data.vstickers()); push(data.vstickers());
}, [&](const MTPDwebPageAttributeUniqueStarGift &data) { }, [&](const MTPDwebPageAttributeUniqueStarGift &data) {
push(data.vgift()); push(data.vgift());
}, [&](const MTPDwebPageAttributeStarGiftCollection &data) {
push(data.vicons());
}); });
} }
void push(const MTPStarGift &data) { void push(const MTPStarGift &data) {

View File

@ -3798,6 +3798,8 @@ void Session::webpageApplyFields(
return (DocumentData*)nullptr; return (DocumentData*)nullptr;
}, [](const MTPDwebPageAttributeUniqueStarGift &) { }, [](const MTPDwebPageAttributeUniqueStarGift &) {
return (DocumentData*)nullptr; return (DocumentData*)nullptr;
}, [](const MTPDwebPageAttributeStarGiftCollection &) {
return (DocumentData*)nullptr;
}); });
if (result) { if (result) {
return result; return result;
@ -3820,6 +3822,14 @@ void Session::webpageApplyFields(
result->items.push_back(processDocument(tl)); result->items.push_back(processDocument(tl));
} }
return result; return result;
}, [&](const MTPDwebPageAttributeStarGiftCollection &data) {
auto result = std::make_unique<WebPageStickerSet>();
result->isEmoji = false;
result->isTextColor = false;
for (const auto &tl : data.vicons().v) {
result->items.push_back(processDocument(tl));
}
return result;
}, [](const auto &) { }, [](const auto &) {
return WebPageStickerSetPtr(nullptr); return WebPageStickerSetPtr(nullptr);
}); });

View File

@ -175,6 +175,8 @@ WebPageType ParseWebPageType(
return WebPageType::StickerSet; return WebPageType::StickerSet;
} else if (type == u"telegram_story_album"_q) { } else if (type == u"telegram_story_album"_q) {
return WebPageType::StoryAlbum; return WebPageType::StoryAlbum;
} else if (type == u"telegram_collection"_q) {
return WebPageType::GiftCollection;
} else if (hasIV) { } else if (hasIV) {
return WebPageType::ArticleWithIV; return WebPageType::ArticleWithIV;
} else { } else {

View File

@ -50,6 +50,7 @@ enum class WebPageType : uint8 {
Story, Story,
StickerSet, StickerSet,
StoryAlbum, StoryAlbum,
GiftCollection,
Article, Article,
ArticleWithIV, ArticleWithIV,

View File

@ -234,6 +234,8 @@ constexpr auto kSponsoredUserpicLines = 2;
? tr::lng_view_button_stickerset(tr::now) ? tr::lng_view_button_stickerset(tr::now)
: (type == WebPageType::StoryAlbum) : (type == WebPageType::StoryAlbum)
? tr::lng_view_button_storyalbum(tr::now) ? tr::lng_view_button_storyalbum(tr::now)
: (type == WebPageType::GiftCollection)
? tr::lng_view_button_collection(tr::now)
: QString()); : QString());
if (page->iv) { if (page->iv) {
const auto manager = &page->owner().customEmojiManager(); const auto manager = &page->owner().customEmojiManager();
@ -272,7 +274,9 @@ constexpr auto kSponsoredUserpicLines = 2;
|| ((type == WebPageType::WallPaper) || ((type == WebPageType::WallPaper)
&& webpage->document && webpage->document
&& webpage->document->isWallPaper()) && webpage->document->isWallPaper())
|| (type == WebPageType::StickerSet); || (type == WebPageType::StickerSet)
|| (type == WebPageType::StoryAlbum)
|| (type == WebPageType::GiftCollection);
} }
} // namespace } // namespace

View File

@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_widget.h"
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "info/common_groups/info_common_groups_widget.h" #include "info/common_groups/info_common_groups_widget.h"
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/stories/info_stories_common.h"
#include "info/info_layer_widget.h" #include "info/info_layer_widget.h"
#include "info/info_section_widget.h" #include "info/info_section_widget.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -476,6 +478,11 @@ Key ContentMemento::key() const {
return Key(poll, pollContextId()); return Key(poll, pollContextId());
} else if (const auto self = settingsSelf()) { } else if (const auto self = settingsSelf()) {
return Settings::Tag{ self }; return Settings::Tag{ self };
} else if (const auto gifts = giftsPeer()) {
return PeerGifts::Tag{
gifts,
giftsCollectionId(),
};
} else if (const auto stories = storiesPeer()) { } else if (const auto stories = storiesPeer()) {
return Stories::Tag{ return Stories::Tag{
stories, stories,
@ -529,6 +536,11 @@ ContentMemento::ContentMemento(Stories::Tag stories)
, _storiesAddToAlbumId(stories.addingToAlbumId) { , _storiesAddToAlbumId(stories.addingToAlbumId) {
} }
ContentMemento::ContentMemento(PeerGifts::Tag gifts)
: _giftsPeer(gifts.peer)
, _giftsCollectionId(gifts.collectionId) {
}
ContentMemento::ContentMemento(Statistics::Tag statistics) ContentMemento::ContentMemento(Statistics::Tag statistics)
: _statisticsTag(statistics) { : _statisticsTag(statistics) {
} }

View File

@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "info/info_wrap_widget.h" #include "info/info_wrap_widget.h"
#include "info/stories/info_stories_common.h"
#include "info/statistics/info_statistics_tag.h" #include "info/statistics/info_statistics_tag.h"
#include "ui/controls/swipe_handler_data.h" #include "ui/controls/swipe_handler_data.h"
@ -61,6 +60,14 @@ namespace Info::GlobalMedia {
struct Tag; struct Tag;
} // namespace Info::GlobalMedia } // namespace Info::GlobalMedia
namespace Info::PeerGifts {
struct Tag;
} // namespace Info::PeerGifts
namespace Info::Stories {
struct Tag;
} // namespace Info::Stories
namespace Info { namespace Info {
class ContentMemento; class ContentMemento;
@ -208,6 +215,7 @@ public:
Data::ForumTopic *topic, Data::ForumTopic *topic,
Data::SavedSublist *sublist, Data::SavedSublist *sublist,
PeerId migratedPeerId); PeerId migratedPeerId);
explicit ContentMemento(PeerGifts::Tag gifts);
explicit ContentMemento(Settings::Tag settings); explicit ContentMemento(Settings::Tag settings);
explicit ContentMemento(Downloads::Tag downloads); explicit ContentMemento(Downloads::Tag downloads);
explicit ContentMemento(Stories::Tag stories); explicit ContentMemento(Stories::Tag stories);
@ -253,6 +261,12 @@ public:
[[nodiscard]] int storiesAddToAlbumId() const { [[nodiscard]] int storiesAddToAlbumId() const {
return _storiesAddToAlbumId; return _storiesAddToAlbumId;
} }
[[nodiscard]] PeerData *giftsPeer() const {
return _giftsPeer;
}
[[nodiscard]] int giftsCollectionId() const {
return _giftsCollectionId;
}
[[nodiscard]] Statistics::Tag statisticsTag() const { [[nodiscard]] Statistics::Tag statisticsTag() const {
return _statisticsTag; return _statisticsTag;
} }
@ -319,6 +333,8 @@ private:
PeerData * const _storiesPeer = nullptr; PeerData * const _storiesPeer = nullptr;
int _storiesAlbumId = 0; int _storiesAlbumId = 0;
int _storiesAddToAlbumId = 0; int _storiesAddToAlbumId = 0;
PeerData * const _giftsPeer = nullptr;
int _giftsCollectionId = 0;
Statistics::Tag _statisticsTag; Statistics::Tag _statisticsTag;
PeerData * const _starrefPeer = nullptr; PeerData * const _starrefPeer = nullptr;
BotStarRef::Type _starrefType = {}; BotStarRef::Type _starrefType = {};

View File

@ -52,6 +52,9 @@ Key::Key(Stories::Tag stories) : _value(stories) {
Key::Key(Statistics::Tag statistics) : _value(statistics) { Key::Key(Statistics::Tag statistics) : _value(statistics) {
} }
Key::Key(PeerGifts::Tag gifts) : _value(gifts) {
}
Key::Key(BotStarRef::Tag starref) : _value(starref) { Key::Key(BotStarRef::Tag starref) : _value(starref) {
} }
@ -132,6 +135,20 @@ int Key::storiesAddToAlbumId() const {
return 0; return 0;
} }
PeerData *Key::giftsPeer() const {
if (const auto tag = std::get_if<PeerGifts::Tag>(&_value)) {
return tag->peer;
}
return nullptr;
}
int Key::giftsCollectionId() const {
if (const auto tag = std::get_if<PeerGifts::Tag>(&_value)) {
return tag->collectionId;
}
return 0;
}
Statistics::Tag Key::statisticsTag() const { Statistics::Tag Key::statisticsTag() const {
if (const auto tag = std::get_if<Statistics::Tag>(&_value)) { if (const auto tag = std::get_if<Statistics::Tag>(&_value)) {
return *tag; return *tag;

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_message_reaction_id.h" #include "data/data_message_reaction_id.h"
#include "data/data_search_controller.h" #include "data/data_search_controller.h"
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/statistics/info_statistics_tag.h" #include "info/statistics/info_statistics_tag.h"
#include "info/stories/info_stories_common.h" #include "info/stories/info_stories_common.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
@ -82,6 +83,7 @@ public:
Key(Downloads::Tag downloads); Key(Downloads::Tag downloads);
Key(Stories::Tag stories); Key(Stories::Tag stories);
Key(Statistics::Tag statistics); Key(Statistics::Tag statistics);
Key(PeerGifts::Tag gifts);
Key(BotStarRef::Tag starref); Key(BotStarRef::Tag starref);
Key(GlobalMedia::Tag global); Key(GlobalMedia::Tag global);
Key(not_null<PollData*> poll, FullMsgId contextId); Key(not_null<PollData*> poll, FullMsgId contextId);
@ -99,6 +101,8 @@ public:
[[nodiscard]] PeerData *storiesPeer() const; [[nodiscard]] PeerData *storiesPeer() const;
[[nodiscard]] int storiesAlbumId() const; [[nodiscard]] int storiesAlbumId() const;
[[nodiscard]] int storiesAddToAlbumId() const; [[nodiscard]] int storiesAddToAlbumId() const;
[[nodiscard]] PeerData *giftsPeer() const;
[[nodiscard]] int giftsCollectionId() const;
[[nodiscard]] Statistics::Tag statisticsTag() const; [[nodiscard]] Statistics::Tag statisticsTag() const;
[[nodiscard]] PeerData *starrefPeer() const; [[nodiscard]] PeerData *starrefPeer() const;
[[nodiscard]] BotStarRef::Type starrefType() const; [[nodiscard]] BotStarRef::Type starrefType() const;
@ -127,6 +131,7 @@ private:
Downloads::Tag, Downloads::Tag,
Stories::Tag, Stories::Tag,
Statistics::Tag, Statistics::Tag,
PeerGifts::Tag,
BotStarRef::Tag, BotStarRef::Tag,
GlobalMedia::Tag, GlobalMedia::Tag,
PollKey, PollKey,
@ -234,6 +239,12 @@ public:
[[nodiscard]] int storiesAddToAlbumId() const { [[nodiscard]] int storiesAddToAlbumId() const {
return key().storiesAddToAlbumId(); return key().storiesAddToAlbumId();
} }
[[nodiscard]] PeerData *giftsPeer() const {
return key().giftsPeer();
}
[[nodiscard]] int giftsCollectionId() const {
return key().giftsCollectionId();
}
[[nodiscard]] Statistics::Tag statisticsTag() const { [[nodiscard]] Statistics::Tag statisticsTag() const {
return key().statisticsTag(); return key().statisticsTag();
} }

View File

@ -211,8 +211,6 @@ std::shared_ptr<ContentMemento> Memento::DefaultContent(
return std::make_shared<SimilarPeers::Memento>(peer); return std::make_shared<SimilarPeers::Memento>(peer);
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:
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

@ -446,7 +446,7 @@ void WrapWidget::setupTopBarMenuToggle() {
addTopBarMenuButton(); addTopBarMenuButton();
} }
}, _topBar->lifetime()); }, _topBar->lifetime());
} else if (section.type() == Section::Type::PeerGifts && key.peer()) { } else if (key.giftsPeer()) {
addTopBarMenuButton(); addTopBarMenuButton();
} }
} }

View File

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_chat_section.h" #include "history/view/history_view_chat_section.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/peer_gifts/info_peer_gifts_widget.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "info/stories/info_stories_widget.h" #include "info/stories/info_stories_widget.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -386,10 +387,7 @@ not_null<Ui::SettingsButton*> AddPeerGiftsButton(
if (navigation->showFrozenError()) { if (navigation->showFrozenError()) {
return; return;
} }
navigation->showSection( navigation->showSection(Info::PeerGifts::Make(peer));
std::make_shared<Info::Memento>(
peer,
Section::Type::PeerGifts));
}); });
return wrap->entity(); return wrap->entity();
} }

View File

@ -47,6 +47,16 @@ class SessionController;
namespace Info::PeerGifts { namespace Info::PeerGifts {
struct Tag {
explicit Tag(not_null<PeerData*> peer, int collectionId = 0)
: peer(peer)
, collectionId(collectionId) {
}
not_null<PeerData*> peer;
int collectionId = 0;
};
struct GiftTypePremium { struct GiftTypePremium {
int64 cost = 0; int64 cost = 0;
QString currency; QString currency;

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_hash.h" #include "api/api_hash.h"
#include "api/api_premium.h" #include "api/api_premium.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "boxes/share_box.h"
#include "boxes/star_gift_box.h" #include "boxes/star_gift_box.h"
#include "core/ui_integration.h" #include "core/ui_integration.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/peer_gifts/info_peer_gifts_collections.h" #include "info/peer_gifts/info_peer_gifts_collections.h"
#include "info/peer_gifts/info_peer_gifts_common.h" #include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "ui/controls/sub_tabs.h" #include "ui/controls/sub_tabs.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
@ -129,6 +131,7 @@ public:
void reloadCollection(int id); void reloadCollection(int id);
void editCollectionGifts(int id); void editCollectionGifts(int id);
void shareCollectionLink(const QString &username, int id);
void editCollectionName(int id); void editCollectionName(int id);
void confirmDeleteCollection(int id); void confirmDeleteCollection(int id);
void collectionAdded(MTPStarGiftCollection result); void collectionAdded(MTPStarGiftCollection result);
@ -209,7 +212,7 @@ private:
std::vector<Data::GiftCollection> _collections; std::vector<Data::GiftCollection> _collections;
Entries _all; Entries _all;
base::flat_map<int, Entries> _perCollection; std::map<int, Entries> _perCollection;
not_null<Entries*> _entries; not_null<Entries*> _entries;
not_null<std::vector<Entry>*> _list; not_null<std::vector<Entry>*> _list;
rpl::variable<Data::GiftsUpdate> _collectionChanges; rpl::variable<Data::GiftsUpdate> _collectionChanges;
@ -811,6 +814,11 @@ void InnerWidget::showMenuForCollection(int id) {
addAction(tr::lng_gift_collection_add_title(tr::now), [=] { addAction(tr::lng_gift_collection_add_title(tr::now), [=] {
editCollectionGifts(id); editCollectionGifts(id);
}, &st::menuIconGiftPremium); }, &st::menuIconGiftPremium);
if (const auto username = _peer->username(); !username.isEmpty()) {
addAction(tr::lng_stories_album_share(tr::now), [=] {
shareCollectionLink(username, id);
}, &st::menuIconShare);
}
addAction(tr::lng_gift_collection_edit(tr::now), [=] { addAction(tr::lng_gift_collection_edit(tr::now), [=] {
editCollectionName(id); editCollectionName(id);
}, &st::menuIconEdit); }, &st::menuIconEdit);
@ -823,6 +831,12 @@ void InnerWidget::showMenuForCollection(int id) {
_menu->popup(QCursor::pos()); _menu->popup(QCursor::pos());
} }
void InnerWidget::shareCollectionLink(const QString &username, int id) {
const auto url = _window->session().createInternalLinkFull(
username + u"/c/"_q + QString::number(id));
FastShareLink(_window, url);
}
void InnerWidget::editCollectionName(int id) { void InnerWidget::editCollectionName(int id) {
const auto done = [=](QString name) { const auto done = [=](QString name) {
collectionRenamed(id, name); collectionRenamed(id, name);
@ -1190,9 +1204,17 @@ void InnerWidget::refreshCollectionsTabs() {
.session = &_window->session(), .session = &_window->session(),
}); });
if (!_collectionsTabs) { if (!_collectionsTabs) {
const auto selectedId = _descriptor.current().collectionId;
const auto selected = (selectedId > 0
&& ranges::contains(
_collections,
selectedId,
&Data::GiftCollection::id))
? QString::number(selectedId)
: u"all"_q;
_collectionsTabs = std::make_unique<Ui::SubTabs>( _collectionsTabs = std::make_unique<Ui::SubTabs>(
this, this,
Ui::SubTabs::Options{ .selected = u"all"_q, .centered = true}, Ui::SubTabs::Options{ .selected = selected, .centered = true },
std::move(tabs), std::move(tabs),
context); context);
_collectionsTabs->show(); _collectionsTabs->show();
@ -1248,7 +1270,7 @@ void InnerWidget::collectionRemoved(int id) {
_descriptorChanges.fire(std::move(now)); _descriptorChanges.fire(std::move(now));
} }
Assert(_entries != &_perCollection[id]); Assert(_entries != &_perCollection[id]);
_perCollection.remove(id); _perCollection.erase(id);
const auto removeFrom = [&](Entries &entries) { const auto removeFrom = [&](Entries &entries) {
for (auto &entry : entries.list) { for (auto &entry : entries.list) {
entry.gift.collectionIds.erase( entry.gift.collectionIds.erase(
@ -1439,8 +1461,14 @@ void InnerWidget::fillMenu(const Ui::Menu::MenuCallback &addAction) {
} }
} }
Memento::Memento(not_null<PeerData*> peer) Memento::Memento(not_null<Controller*> controller)
: ContentMemento(peer, nullptr, nullptr, PeerId()) { : ContentMemento(Tag{
controller->giftsPeer(),
controller->giftsCollectionId() }) {
}
Memento::Memento(not_null<PeerData*> peer, int collectionId)
: ContentMemento(Tag{ peer, collectionId }) {
} }
Section Memento::section() const { Section Memento::section() const {
@ -1451,7 +1479,7 @@ 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, peer()); auto result = object_ptr<Widget>(parent, controller);
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
return result; return result;
} }
@ -1466,16 +1494,16 @@ std::unique_ptr<ListState> Memento::listState() {
Memento::~Memento() = default; Memento::~Memento() = default;
Widget::Widget( Widget::Widget(QWidget *parent, not_null<Controller*> controller)
QWidget *parent, : ContentWidget(parent, controller)
not_null<Controller*> controller, , _descriptor(Descriptor{
not_null<PeerData*> peer) .collectionId = controller->giftsCollectionId(),
: ContentWidget(parent, controller) { }) {
_inner = setInnerWidget( _inner = setInnerWidget(
object_ptr<InnerWidget>( object_ptr<InnerWidget>(
this, this,
controller->parentController(), controller->parentController(),
peer, controller->giftsPeer(),
_descriptor.value())); _descriptor.value()));
_inner->notifyEnabled( _inner->notifyEnabled(
) | rpl::take(1) | rpl::start_with_next([=](bool enabled) { ) | rpl::take(1) | rpl::start_with_next([=](bool enabled) {
@ -1694,7 +1722,7 @@ void Widget::setInternalState(
} }
std::shared_ptr<ContentMemento> Widget::doCreateMemento() { std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
auto result = std::make_shared<Memento>(peer()); auto result = std::make_shared<Memento>(controller());
saveState(result.get()); saveState(result.get());
return result; return result;
} }
@ -1709,4 +1737,11 @@ void Widget::restoreState(not_null<Memento*> memento) {
scrollTopRestore(memento->scrollTop()); scrollTopRestore(memento->scrollTop());
} }
std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer, int albumId) {
return std::make_shared<Info::Memento>(
std::vector<std::shared_ptr<ContentMemento>>(
1,
std::make_shared<Memento>(peer, albumId)));
}
} // namespace Info::PeerGifts } // namespace Info::PeerGifts

View File

@ -58,7 +58,9 @@ class InnerWidget;
class Memento final : public ContentMemento { class Memento final : public ContentMemento {
public: public:
explicit Memento(not_null<PeerData*> peer); Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer, int collectionId);
~Memento();
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
@ -70,8 +72,6 @@ public:
void setListState(std::unique_ptr<ListState> state); void setListState(std::unique_ptr<ListState> state);
std::unique_ptr<ListState> listState(); std::unique_ptr<ListState> listState();
~Memento();
private: private:
std::unique_ptr<ListState> _listState; std::unique_ptr<ListState> _listState;
@ -79,10 +79,7 @@ private:
class Widget final : public ContentWidget { class Widget final : public ContentWidget {
public: public:
Widget( Widget(QWidget *parent, not_null<Controller*> controller);
QWidget *parent,
not_null<Controller*> controller,
not_null<PeerData*> peer);
[[nodiscard]] not_null<PeerData*> peer() const; [[nodiscard]] not_null<PeerData*> peer() const;
@ -120,4 +117,8 @@ private:
}; };
[[nodiscard]] std::shared_ptr<Info::Memento> Make(
not_null<PeerData*> peer,
int collectionId = 0);
} // namespace Info::PeerGifts } // namespace Info::PeerGifts

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_stories_list.h" #include "dialogs/ui/dialogs_stories_list.h"
#include "info/media/info_media_buttons.h" #include "info/media/info_media_buttons.h"
#include "info/media/info_media_list_widget.h" #include "info/media/info_media_list_widget.h"
#include "info/peer_gifts/info_peer_gifts_widget.h"
#include "info/profile/info_profile_actions.h" #include "info/profile/info_profile_actions.h"
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
@ -456,10 +457,7 @@ void InnerWidget::addGiftsButton(Ui::MultiSlideTracker &tracker) {
const auto gifts = giftsWrap->entity(); const auto gifts = giftsWrap->entity();
gifts->addClickHandler([=] { gifts->addClickHandler([=] {
_controller->showSection( _controller->showSection(PeerGifts::Make(_peer));
std::make_shared<Info::Memento>(
user,
Section::Type::PeerGifts));
}); });
auto label = rpl::duplicate( auto label = rpl::duplicate(
count count

View File

@ -25,7 +25,8 @@ int ArchiveId() {
Memento::Memento(not_null<Controller*> controller) Memento::Memento(not_null<Controller*> controller)
: ContentMemento(Tag{ : ContentMemento(Tag{
controller->storiesPeer(), controller->storiesPeer(),
controller->storiesAlbumId() }) controller->storiesAlbumId(),
controller->storiesAddToAlbumId() })
, _media(controller) { , _media(controller) {
} }

View File

@ -1289,6 +1289,7 @@ webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settin
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = WebPageAttribute; webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = WebPageAttribute;
webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute;
webPageAttributeStarGiftCollection#31cad303 icons:Vector<Document> = WebPageAttribute;
messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList; messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;

View File

@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/channel_statistics/earn/earn_format.h" #include "info/channel_statistics/earn/earn_format.h"
#include "info/channel_statistics/earn/earn_icons.h" #include "info/channel_statistics/earn/earn_icons.h"
#include "info/peer_gifts/info_peer_gifts_common.h" #include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/peer_gifts/info_peer_gifts_widget.h"
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData. #include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
#include "info/statistics/info_statistics_list_controllers.h" #include "info/statistics/info_statistics_list_controllers.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -1775,9 +1776,7 @@ void GenericCreditsEntryBox(
if (ok && showSection) { if (ok && showSection) {
if (const auto window = show->resolveWindow()) { if (const auto window = show->resolveWindow()) {
window->showSection( window->showSection(
std::make_shared<Info::Memento>( Info::PeerGifts::Make(window->session().user()));
window->session().user(),
Info::Section::Type::PeerGifts));
} }
} }
if (const auto strong = weak.get()) { if (const auto strong = weak.get()) {

View File

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_filters_menu.h" #include "window/window_filters_menu.h"
#include "window/window_separate_id.h" #include "window/window_separate_id.h"
#include "info/channel_statistics/earn/info_channel_earn_list.h" #include "info/channel_statistics/earn/info_channel_earn_list.h"
#include "info/peer_gifts/info_peer_gifts_widget.h"
#include "info/stories/info_stories_widget.h" #include "info/stories/info_stories_widget.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h" #include "info/info_controller.h"
@ -655,6 +656,8 @@ void SessionNavigation::showPeerByLinkResolved(
})); }));
} else if (info.storyAlbumId > 0) { } else if (info.storyAlbumId > 0) {
showSection(Info::Stories::Make(peer, info.storyAlbumId)); showSection(Info::Stories::Make(peer, info.storyAlbumId));
} else if (info.giftCollectionId > 0) {
showSection(Info::PeerGifts::Make(peer, info.giftCollectionId));
} else if (bot && resolveType == ResolveType::BotApp) { } else if (bot && resolveType == ResolveType::BotApp) {
const auto itemId = info.clickFromMessageId; const auto itemId = info.clickFromMessageId;
const auto item = _session->data().message(itemId); const auto item = _session->data().message(itemId);

View File

@ -41,6 +41,7 @@ struct PeerByLinkInfo {
MsgId messageId = ShowAtUnreadMsgId; MsgId messageId = ShowAtUnreadMsgId;
StoryId storyId = 0; StoryId storyId = 0;
int storyAlbumId = 0; int storyAlbumId = 0;
int giftCollectionId = 0;
std::optional<TimeId> videoTimestamp; std::optional<TimeId> videoTimestamp;
QString text; QString text;
RepliesByLinkInfo repliesInfo; RepliesByLinkInfo repliesInfo;