2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-22 02:07:24 +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_all" = "All Gifts";
"lng_gift_collection_add_title" = "Add Gifts";
"lng_gift_collection_share" = "Share Collection";
"lng_gift_collection_edit" = "Edit Name";
"lng_gift_collection_limit_title" = "Limit Reached";
"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_call" = "Join call";
"lng_view_button_storyalbum" = "View Album";
"lng_view_button_collection" = "View Collection";
"lng_sponsored_hide_ads" = "Hide";
"lng_sponsored_title" = "What are sponsored messages?";

View File

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

View File

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

View File

@ -3798,6 +3798,8 @@ void Session::webpageApplyFields(
return (DocumentData*)nullptr;
}, [](const MTPDwebPageAttributeUniqueStarGift &) {
return (DocumentData*)nullptr;
}, [](const MTPDwebPageAttributeStarGiftCollection &) {
return (DocumentData*)nullptr;
});
if (result) {
return result;
@ -3820,6 +3822,14 @@ void Session::webpageApplyFields(
result->items.push_back(processDocument(tl));
}
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 &) {
return WebPageStickerSetPtr(nullptr);
});

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "info/info_wrap_widget.h"
#include "info/stories/info_stories_common.h"
#include "info/statistics/info_statistics_tag.h"
#include "ui/controls/swipe_handler_data.h"
@ -61,6 +60,14 @@ namespace Info::GlobalMedia {
struct Tag;
} // namespace Info::GlobalMedia
namespace Info::PeerGifts {
struct Tag;
} // namespace Info::PeerGifts
namespace Info::Stories {
struct Tag;
} // namespace Info::Stories
namespace Info {
class ContentMemento;
@ -208,6 +215,7 @@ public:
Data::ForumTopic *topic,
Data::SavedSublist *sublist,
PeerId migratedPeerId);
explicit ContentMemento(PeerGifts::Tag gifts);
explicit ContentMemento(Settings::Tag settings);
explicit ContentMemento(Downloads::Tag downloads);
explicit ContentMemento(Stories::Tag stories);
@ -253,6 +261,12 @@ public:
[[nodiscard]] int storiesAddToAlbumId() const {
return _storiesAddToAlbumId;
}
[[nodiscard]] PeerData *giftsPeer() const {
return _giftsPeer;
}
[[nodiscard]] int giftsCollectionId() const {
return _giftsCollectionId;
}
[[nodiscard]] Statistics::Tag statisticsTag() const {
return _statisticsTag;
}
@ -319,6 +333,8 @@ private:
PeerData * const _storiesPeer = nullptr;
int _storiesAlbumId = 0;
int _storiesAddToAlbumId = 0;
PeerData * const _giftsPeer = nullptr;
int _giftsCollectionId = 0;
Statistics::Tag _statisticsTag;
PeerData * const _starrefPeer = nullptr;
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(PeerGifts::Tag gifts) : _value(gifts) {
}
Key::Key(BotStarRef::Tag starref) : _value(starref) {
}
@ -132,6 +135,20 @@ int Key::storiesAddToAlbumId() const {
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 {
if (const auto tag = std::get_if<Statistics::Tag>(&_value)) {
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_search_controller.h"
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "info/statistics/info_statistics_tag.h"
#include "info/stories/info_stories_common.h"
#include "window/window_session_controller.h"
@ -82,6 +83,7 @@ public:
Key(Downloads::Tag downloads);
Key(Stories::Tag stories);
Key(Statistics::Tag statistics);
Key(PeerGifts::Tag gifts);
Key(BotStarRef::Tag starref);
Key(GlobalMedia::Tag global);
Key(not_null<PollData*> poll, FullMsgId contextId);
@ -99,6 +101,8 @@ public:
[[nodiscard]] PeerData *storiesPeer() const;
[[nodiscard]] int storiesAlbumId() const;
[[nodiscard]] int storiesAddToAlbumId() const;
[[nodiscard]] PeerData *giftsPeer() const;
[[nodiscard]] int giftsCollectionId() const;
[[nodiscard]] Statistics::Tag statisticsTag() const;
[[nodiscard]] PeerData *starrefPeer() const;
[[nodiscard]] BotStarRef::Type starrefType() const;
@ -127,6 +131,7 @@ private:
Downloads::Tag,
Stories::Tag,
Statistics::Tag,
PeerGifts::Tag,
BotStarRef::Tag,
GlobalMedia::Tag,
PollKey,
@ -234,6 +239,12 @@ public:
[[nodiscard]] int storiesAddToAlbumId() const {
return key().storiesAddToAlbumId();
}
[[nodiscard]] PeerData *giftsPeer() const {
return key().giftsPeer();
}
[[nodiscard]] int giftsCollectionId() const {
return key().giftsCollectionId();
}
[[nodiscard]] Statistics::Tag statisticsTag() const {
return key().statisticsTag();
}

View File

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

View File

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

View File

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

View File

@ -47,6 +47,16 @@ class SessionController;
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 {
int64 cost = 0;
QString currency;

View File

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

View File

@ -58,7 +58,9 @@ class InnerWidget;
class Memento final : public ContentMemento {
public:
explicit Memento(not_null<PeerData*> peer);
Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer, int collectionId);
~Memento();
object_ptr<ContentWidget> createWidget(
QWidget *parent,
@ -70,8 +72,6 @@ public:
void setListState(std::unique_ptr<ListState> state);
std::unique_ptr<ListState> listState();
~Memento();
private:
std::unique_ptr<ListState> _listState;
@ -79,10 +79,7 @@ private:
class Widget final : public ContentWidget {
public:
Widget(
QWidget *parent,
not_null<Controller*> controller,
not_null<PeerData*> peer);
Widget(QWidget *parent, not_null<Controller*> controller);
[[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

View File

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

View File

@ -25,7 +25,8 @@ int ArchiveId() {
Memento::Memento(not_null<Controller*> controller)
: ContentMemento(Tag{
controller->storiesPeer(),
controller->storiesAlbumId() })
controller->storiesAlbumId(),
controller->storiesAddToAlbumId() })
, _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;
webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = 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;

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_icons.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/statistics/info_statistics_list_controllers.h"
#include "info/info_controller.h"
@ -1775,9 +1776,7 @@ void GenericCreditsEntryBox(
if (ok && showSection) {
if (const auto window = show->resolveWindow()) {
window->showSection(
std::make_shared<Info::Memento>(
window->session().user(),
Info::Section::Type::PeerGifts));
Info::PeerGifts::Make(window->session().user()));
}
}
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_separate_id.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/info_memento.h"
#include "info/info_controller.h"
@ -655,6 +656,8 @@ void SessionNavigation::showPeerByLinkResolved(
}));
} else if (info.storyAlbumId > 0) {
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) {
const auto itemId = info.clickFromMessageId;
const auto item = _session->data().message(itemId);

View File

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