diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 51342a8cc..f46ba6968 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1095,6 +1095,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stickers_count#one" = "{count} sticker"; "lng_stickers_count#other" = "{count} stickers"; "lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps."; +"lng_stickers_attached_sets" = "Sets of attached stickers"; "lng_stickers_group_set" = "Group sticker set"; "lng_stickers_remove_group_set" = "Remove group sticker set?"; "lng_stickers_group_from_your" = "Choose from your stickers"; @@ -1256,6 +1257,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_copy_text" = "Copy Text"; "lng_context_open_gif" = "Open GIF"; "lng_context_save_gif" = "Save GIF"; +"lng_context_attached_stickers" = "Attached Stickers"; "lng_context_to_msg" = "Go To Message"; "lng_context_reply_msg" = "Reply"; "lng_context_edit_msg" = "Edit"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 34e813cda..6c63bbe8b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -36,6 +36,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "auth_session.h" #include "boxes/confirm_box.h" +#include "boxes/stickers_box.h" +#include "boxes/sticker_set_box.h" #include "window/notifications_manager.h" #include "window/window_lock_widgets.h" #include "window/window_controller.h" @@ -2624,6 +2626,37 @@ void ApiWrap::resolveWebPages() { } } +void ApiWrap::requestAttachedStickerSets(not_null photo) { + request(_attachedStickerSetsRequestId).cancel(); + _attachedStickerSetsRequestId = request(MTPmessages_GetAttachedStickers( + MTP_inputStickeredMediaPhoto(photo->mtpInput()) + )).done([=](const MTPVector &result) { + if (result.v.isEmpty()) { + Ui::show(Box(lang(lng_stickers_not_found))); + return; + } else if (result.v.size() > 1) { + Ui::show(Box(result)); + return; + } + // Single attached sticker pack. + const auto setData = result.v.front().match([&](const auto &data) { + return data.vset.match([&](const MTPDstickerSet &data) { + return &data; + }); + }); + + const auto setId = (setData->vid.v && setData->vaccess_hash.v) + ? MTP_inputStickerSetID(setData->vid, setData->vaccess_hash) + : MTP_inputStickerSetShortName(setData->vshort_name); + Ui::show( + Box(setId), + LayerOption::KeepOther); + + }).fail([=](const RPCError &error) { + Ui::show(Box(lang(lng_stickers_not_found))); + }).send(); +} + void ApiWrap::requestParticipantsCountDelayed( not_null channel) { _participantsCountRequestTimer.call( diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index fd63d6fc6..b4d88fe59 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -172,6 +172,7 @@ public: void clearWebPageRequest(WebPageData *page); void clearWebPageRequests(); + void requestAttachedStickerSets(not_null photo); void scheduleStickerSetRequest(uint64 setId, uint64 access); void requestStickerSets(); void saveStickerSets( @@ -794,4 +795,6 @@ private: std::optional _contactSignupSilent; rpl::event_stream _contactSignupSilentChanges; + mtpRequestId _attachedStickerSetsRequestId = 0; + }; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 78632eae8..33cdeff24 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -145,6 +145,39 @@ StickersBox::StickersBox(QWidget*, not_null megagroup) subscribe(_installed.widget()->scrollToY, [this](int y) { onScrollToY(y); }); } +StickersBox::StickersBox(QWidget*, const MTPVector &attachedSets) +: _section(Section::Attached) +, _attached(0, this, Section::Attached) +, _attachedSets(attachedSets) { +} + +void StickersBox::showAttachedStickers() { + auto addedSet = false; + for (const auto &stickerSet : _attachedSets.v) { + const auto setData = stickerSet.match([&](const auto &data) { + return data.vset.match([&](const MTPDstickerSet &data) { + return &data; + }); + }); + + if (const auto set = Stickers::FeedSet(*setData)) { + if (_attached.widget()->appendSet(*set)) { + addedSet = true; + if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) { + Auth().api().scheduleStickerSetRequest(set->id, set->access); + } + } + } + } + if (addedSet) { + _attached.widget()->updateSize(); + } + + if (_section == Section::Attached && addedSet) { + Auth().api().requestStickerSets(); + } +} + void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) { _archivedRequestId = 0; _archivedLoaded = true; @@ -226,6 +259,8 @@ void StickersBox::prepare() { } } else if (_section == Section::Archived) { requestArchivedSets(); + } else if (_section == Section::Attached) { + setTitle(langFactory(lng_stickers_attached_sets)); } if (_tabs) { if (Auth().data().archivedStickerSetsOrder().isEmpty()) { @@ -241,6 +276,7 @@ void StickersBox::prepare() { if (_installed.widget() && _section != Section::Installed) _installed.widget()->hide(); if (_featured.widget() && _section != Section::Featured) _featured.widget()->hide(); if (_archived.widget() && _section != Section::Archived) _archived.widget()->hide(); + if (_attached.widget() && _section != Section::Attached) _attached.widget()->hide(); if (_featured.widget()) { _featured.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); @@ -249,18 +285,25 @@ void StickersBox::prepare() { _archived.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); _archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); }); } + if (_attached.widget()) { + _attached.widget()->setInstallSetCallback([this](uint64 setId) { installSet(setId); }); + _attached.widget()->setLoadMoreCallback([this] { showAttachedStickers(); }); + } if (_megagroupSet) { addButton(langFactory(lng_settings_save), [this] { _installed.widget()->saveGroupSet(); closeBox(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); } else { - addButton(langFactory(lng_about_done), [this] { closeBox(); }); + const auto close = _section == Section::Attached; + addButton(langFactory(close ? lng_close : lng_about_done), [this] { closeBox(); }); } if (_section == Section::Installed) { _tab = &_installed; } else if (_section == Section::Archived) { _tab = &_archived; + } else if (_section == Section::Attached) { + _tab = &_attached; } else { // _section == Section::Featured _tab = &_featured; } @@ -448,7 +491,8 @@ void StickersBox::installSet(uint64 setId) { _localRemoved.removeOne(setId); if (_installed.widget()) _installed.widget()->setRemovedSets(_localRemoved); if (_featured.widget()) _featured.widget()->setRemovedSets(_localRemoved); - _archived.widget()->setRemovedSets(_localRemoved); + if (_archived.widget()) _archived.widget()->setRemovedSets(_localRemoved); + if (_attached.widget()) _attached.widget()->setRemovedSets(_localRemoved); } if (!(it->flags & MTPDstickerSet::Flag::f_installed_date) || (it->flags & MTPDstickerSet::Flag::f_archived)) { @@ -521,6 +565,7 @@ void StickersBox::resizeEvent(QResizeEvent *e) { if (_installed.widget()) _installed.widget()->resize(width(), _installed.widget()->height()); if (_featured.widget()) _featured.widget()->resize(width(), _featured.widget()->height()); if (_archived.widget()) _archived.widget()->resize(width(), _archived.widget()->height()); + if (_attached.widget()) _attached.widget()->resize(width(), _attached.widget()->height()); } void StickersBox::handleStickersUpdated() { @@ -537,6 +582,7 @@ void StickersBox::handleStickersUpdated() { } void StickersBox::rebuildList(Tab *tab) { + if (_section == Section::Attached) return; if (!tab) tab = _tab; if (tab == &_installed) { diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index a406bc6fc..3e01ec9be 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -33,9 +33,11 @@ public: Installed, Featured, Archived, + Attached, }; StickersBox(QWidget*, Section section); StickersBox(QWidget*, not_null megagroup); + StickersBox(QWidget*, const MTPVector &attachedSets); void setInnerFocus() override; @@ -97,6 +99,7 @@ private: void requestArchivedSets(); void loadMoreArchived(); void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); + void showAttachedStickers(); object_ptr _tabs = { nullptr }; QList
_tabIndices; @@ -109,8 +112,11 @@ private: Tab _installed; Tab _featured; Tab _archived; + Tab _attached; Tab *_tab = nullptr; + const MTPVector _attachedSets; + ChannelData *_megagroupSet = nullptr; std::unique_ptr _slideAnimation; diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index d668c4d0a..70ba5beef 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -75,6 +75,7 @@ public: uint64 access = 0; QByteArray fileReference; TimeId date = 0; + bool hasSticker = false; PeerData *peer = nullptr; // for chat and channel photos connection // geo, caption diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index a0691aadf..eb8f38519 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1661,6 +1661,7 @@ not_null Session::processPhoto( data.vaccess_hash.v, data.vfile_reference.v, data.vdate.v, + data.is_has_stickers(), thumbnailInline, thumbnailSmall, thumbnail, @@ -1675,6 +1676,7 @@ not_null Session::photo( const uint64 &access, const QByteArray &fileReference, TimeId date, + bool hasSticker, const ImagePtr &thumbnailInline, const ImagePtr &thumbnailSmall, const ImagePtr &thumbnail, @@ -1685,6 +1687,7 @@ not_null Session::photo( access, fileReference, date, + hasSticker, thumbnailInline, thumbnailSmall, thumbnail, @@ -1747,6 +1750,7 @@ PhotoData *Session::photoFromWeb( uint64(0), QByteArray(), unixtime(), + false, thumbnailInline, thumbnailSmall, thumbnail, @@ -1796,6 +1800,7 @@ void Session::photoApplyFields( data.vaccess_hash.v, data.vfile_reference.v, data.vdate.v, + data.is_has_stickers(), thumbnailInline, thumbnailSmall, thumbnail, @@ -1808,6 +1813,7 @@ void Session::photoApplyFields( const uint64 &access, const QByteArray &fileReference, TimeId date, + bool hasSticker, const ImagePtr &thumbnailInline, const ImagePtr &thumbnailSmall, const ImagePtr &thumbnail, @@ -1818,6 +1824,7 @@ void Session::photoApplyFields( photo->access = access; photo->fileReference = fileReference; photo->date = date; + photo->hasSticker = hasSticker; photo->updateImages( thumbnailInline, thumbnailSmall, diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 0a99abc5d..50c5de0f6 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -342,6 +342,7 @@ public: const uint64 &access, const QByteArray &fileReference, TimeId date, + bool hasSticker, const ImagePtr &thumbnailInline, const ImagePtr &thumbnailSmall, const ImagePtr &thumbnail, @@ -574,6 +575,7 @@ private: const uint64 &access, const QByteArray &fileReference, TimeId date, + bool hasSticker, const ImagePtr &thumbnailInline, const ImagePtr &thumbnailSmall, const ImagePtr &thumbnail, diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 1a783525f..b14bc5ea1 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1510,6 +1510,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang(lng_context_copy_image), [=] { copyContextImage(photo); }); + if (photo->hasSticker) { + _menu->addAction(lang(lng_context_attached_stickers), [=] { + Auth().api().requestAttachedStickerSets(photo); + }); + } }; const auto addDocumentActions = [&](not_null document) { if (document->loading()) { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 8ec85ade0..ce540d31c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/view/media_view_overlay_widget.h" +#include "apiwrap.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" @@ -462,6 +463,9 @@ void OverlayWidget::updateActions() { if ((_doc && fileShown()) || (_photo && _photo->loaded())) { _actions.push_back({ lang(lng_mediaview_copy), SLOT(onCopy()) }); } + if (_photo && _photo->hasSticker) { + _actions.push_back({ lang(lng_context_attached_stickers), SLOT(onAttachedStickers()) }); + } if (_canForwardItem) { _actions.push_back({ lang(lng_mediaview_forward), SLOT(onForward()) }); } @@ -1108,6 +1112,11 @@ void OverlayWidget::onCopy() { } } +void OverlayWidget::onAttachedStickers() { + close(); + Auth().api().requestAttachedStickerSets(_photo); +} + std::optional OverlayWidget::sharedMediaType() const { using Type = SharedMediaType; if (const auto item = App::histItemById(_msgid)) { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 0533b312c..7cd9ece42 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -97,6 +97,7 @@ private slots: void onCopy(); void onMenuDestroy(QObject *obj); void receiveMouse(); + void onAttachedStickers(); void onDropdown();