diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 760826e7e..c9714d67e 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtproto_dc_options.h" #include "data/notify/data_notify_settings.h" #include "data/stickers/data_stickers.h" +#include "data/data_saved_messages.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/data_chat.h" @@ -2208,6 +2209,16 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updatePinnedSavedDialogs: { + session().data().savedMessages().apply( + update.c_updatePinnedSavedDialogs()); + } break; + + case mtpc_updateSavedDialogPinned: { + session().data().savedMessages().apply( + update.c_updateSavedDialogPinned()); + } break; + case mtpc_updateChannel: { auto &d = update.c_updateChannel(); if (const auto channel = session().data().channelLoaded(d.vchannel_id())) { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index c3070b99f..a247ad196 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_folder.h" #include "data/data_forum_topic.h" #include "data/data_forum.h" +#include "data/data_saved_sublist.h" #include "data/data_search_controller.h" #include "data/data_scheduled_messages.h" #include "data/data_session.h" @@ -443,8 +444,8 @@ void ApiWrap::savePinnedOrder(not_null forum) { void ApiWrap::savePinnedOrder(not_null saved) { const auto &order = _session->data().pinnedChatsOrder(saved); const auto input = [](Dialogs::Key key) { - if (const auto history = key.history()) { - return MTP_inputDialogPeer(history->peer->input); + if (const auto sublist = key.sublist()) { + return MTP_inputDialogPeer(sublist->peer()->input); } Unexpected("Key type in pinnedDialogsOrder()."); }; diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.cpp b/Telegram/SourceFiles/boxes/premium_limits_box.cpp index 64452a906..60eb5ecde 100644 --- a/Telegram/SourceFiles/boxes/premium_limits_box.cpp +++ b/Telegram/SourceFiles/boxes/premium_limits_box.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/data_channel.h" #include "data/data_forum.h" +#include "data/data_saved_messages.h" #include "data/data_session.h" #include "data/data_folder.h" #include "data/data_premium_limits.h" @@ -882,6 +883,18 @@ void PinsLimitBox( limits.dialogsPinnedPremium(), PinsCount(session->data().chatsList())); } +void SublistsPinsLimitBox( + not_null box, + not_null session) { + const auto limits = Data::PremiumLimits(session); + SimplePinsLimitBox( + box, + session, + "saved_dialog_pinned", + limits.savedSublistsPinnedDefault(), + limits.savedSublistsPinnedPremium(), + PinsCount(session->data().savedMessages().chatsList())); +} void ForumPinsLimitBox( not_null box, diff --git a/Telegram/SourceFiles/boxes/premium_limits_box.h b/Telegram/SourceFiles/boxes/premium_limits_box.h index 5a4fa8a0a..8640dc235 100644 --- a/Telegram/SourceFiles/boxes/premium_limits_box.h +++ b/Telegram/SourceFiles/boxes/premium_limits_box.h @@ -60,6 +60,9 @@ void PinsLimitBox( void ForumPinsLimitBox( not_null box, not_null forum); +void SublistsPinsLimitBox( + not_null box, + not_null session); void CaptionLimitBox( not_null box, not_null session, diff --git a/Telegram/SourceFiles/data/data_saved_messages.cpp b/Telegram/SourceFiles/data/data_saved_messages.cpp index 39ee85fa8..9fd28f735 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.cpp +++ b/Telegram/SourceFiles/data/data_saved_messages.cpp @@ -62,54 +62,19 @@ not_null SavedMessages::sublist(not_null peer) { void SavedMessages::loadMore() { if (_loadMoreRequestId || _chatsList.loaded()) { return; + } else if (!_pinnedLoaded) { + loadPinned(); } _loadMoreRequestId = _owner->session().api().request( MTPmessages_GetSavedDialogs( - MTP_flags(0), + MTP_flags(MTPmessages_GetSavedDialogs::Flag::f_exclude_pinned), MTP_int(_offsetDate), MTP_int(_offsetId), _offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(), MTP_int(kPerPage), MTP_long(0)) // hash ).done([=](const MTPmessages_SavedDialogs &result) { - auto list = (const QVector*)nullptr; - result.match([](const MTPDmessages_savedDialogsNotModified &) { - LOG(("API Error: messages.savedDialogsNotModified.")); - }, [&](const auto &data) { - _owner->processUsers(data.vusers()); - _owner->processChats(data.vchats()); - _owner->processMessages( - data.vmessages(), - NewMessageType::Existing); - list = &data.vdialogs().v; - }); - _loadMoreRequestId = 0; - if (!list) { - _chatsList.setLoaded(); - return; - } - auto lastValid = false; - const auto selfId = _owner->session().userPeerId(); - for (const auto &dialog : *list) { - const auto &data = dialog.data(); - const auto peer = _owner->peer(peerFromMTP(data.vpeer())); - const auto topId = MsgId(data.vtop_message().v); - if (const auto item = _owner->message(selfId, topId)) { - _offsetPeer = peer; - _offsetDate = item->date(); - _offsetId = topId; - lastValid = true; - sublist(peer)->applyMaybeLast(item); - } else { - lastValid = false; - } - } - if (!lastValid) { - LOG(("API Error: Unknown message in the end of a slice.")); - _chatsList.setLoaded(); - } else if (result.type() == mtpc_messages_savedDialogs) { - _chatsList.setLoaded(); - } + apply(result, false); }).fail([=](const MTP::Error &error) { if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) { _unsupported = true; @@ -119,6 +84,24 @@ void SavedMessages::loadMore() { }).send(); } +void SavedMessages::loadPinned() { + if (_pinnedRequestId) { + return; + } + _pinnedRequestId = _owner->session().api().request( + MTPmessages_GetPinnedSavedDialogs() + ).done([=](const MTPmessages_SavedDialogs &result) { + apply(result, true); + }).fail([=](const MTP::Error &error) { + if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) { + _unsupported = true; + } else { + _pinnedLoaded = true; + } + _pinnedRequestId = 0; + }).send(); +} + void SavedMessages::loadMore(not_null sublist) { if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) { return; @@ -185,4 +168,109 @@ void SavedMessages::loadMore(not_null sublist) { _loadMoreRequests[sublist] = requestId; } +void SavedMessages::apply( + const MTPmessages_SavedDialogs &result, + bool pinned) { + auto list = (const QVector*)nullptr; + result.match([](const MTPDmessages_savedDialogsNotModified &) { + LOG(("API Error: messages.savedDialogsNotModified.")); + }, [&](const auto &data) { + _owner->processUsers(data.vusers()); + _owner->processChats(data.vchats()); + _owner->processMessages( + data.vmessages(), + NewMessageType::Existing); + list = &data.vdialogs().v; + }); + if (pinned) { + _pinnedRequestId = 0; + _pinnedLoaded = true; + } else { + _loadMoreRequestId = 0; + } + if (!list) { + if (!pinned) { + _chatsList.setLoaded(); + } + return; + } + auto lastValid = false; + auto offsetDate = TimeId(); + auto offsetId = MsgId(); + auto offsetPeer = (PeerData*)nullptr; + const auto selfId = _owner->session().userPeerId(); + for (const auto &dialog : *list) { + const auto &data = dialog.data(); + const auto peer = _owner->peer(peerFromMTP(data.vpeer())); + const auto topId = MsgId(data.vtop_message().v); + if (const auto item = _owner->message(selfId, topId)) { + offsetPeer = peer; + offsetDate = item->date(); + offsetId = topId; + lastValid = true; + const auto entry = sublist(peer); + const auto entryPinned = pinned || data.is_pinned(); + entry->applyMaybeLast(item); + _owner->setPinnedFromEntryList(entry, entryPinned); + } else { + lastValid = false; + } + } + if (pinned) { + } else if (!lastValid) { + LOG(("API Error: Unknown message in the end of a slice.")); + _chatsList.setLoaded(); + } else if (result.type() == mtpc_messages_savedDialogs) { + _chatsList.setLoaded(); + } else if (offsetDate < _offsetDate + || (offsetDate == _offsetDate && offsetId == _offsetId && offsetPeer == _offsetPeer)) { + LOG(("API Error: Bad order in messages.savedDialogs.")); + _chatsList.setLoaded(); + } else { + _offsetDate = offsetDate; + _offsetId = offsetId; + _offsetPeer = offsetPeer; + } +} + +void SavedMessages::apply(const MTPDupdatePinnedSavedDialogs &update) { + const auto list = update.vorder(); + if (!list) { + loadPinned(); + return; + } + const auto &order = list->v; + const auto notLoaded = [&](const MTPDialogPeer &peer) { + return peer.match([&](const MTPDdialogPeer &data) { + const auto peer = _owner->peer(peerFromMTP(data.vpeer())); + return !_sublists.contains(peer); + }, [&](const MTPDdialogPeerFolder &data) { + LOG(("API Error: " + "updatePinnedSavedDialogs has folders.")); + return false; + }); + }; + if (!ranges::none_of(order, notLoaded)) { + loadPinned(); + } else { + _chatsList.pinned()->applyList(_owner, order); + _owner->notifyPinnedDialogsOrderUpdated(); + } +} + +void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) { + update.vpeer().match([&](const MTPDdialogPeer &data) { + const auto peer = _owner->peer(peerFromMTP(data.vpeer())); + const auto i = _sublists.find(peer); + if (i != end(_sublists)) { + const auto entry = i->second.get(); + _owner->setChatPinned(entry, FilterId(), update.is_pinned()); + } else { + loadPinned(); + } + }, [&](const MTPDdialogPeerFolder &data) { + DEBUG_LOG(("API Error: Folder in updateSavedDialogPinned.")); + }); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/data_saved_messages.h b/Telegram/SourceFiles/data/data_saved_messages.h index dd68f4bb8..3fbc5a772 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.h +++ b/Telegram/SourceFiles/data/data_saved_messages.h @@ -34,7 +34,13 @@ public: void loadMore(); void loadMore(not_null sublist); + void apply(const MTPDupdatePinnedSavedDialogs &update); + void apply(const MTPDupdateSavedDialogPinned &update); + private: + void loadPinned(); + void apply(const MTPmessages_SavedDialogs &result, bool pinned); + const not_null _owner; Dialogs::MainList _chatsList; @@ -44,11 +50,13 @@ private: base::flat_map, mtpRequestId> _loadMoreRequests; mtpRequestId _loadMoreRequestId = 0; + mtpRequestId _pinnedRequestId = 0; TimeId _offsetDate = 0; MsgId _offsetId = 0; PeerData *_offsetPeer = nullptr; + bool _pinnedLoaded = false; bool _unsupported = false; }; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index edc79bb35..6001a46c2 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2107,13 +2107,17 @@ void Session::applyDialog( setPinnedFromEntryList(folder, data.is_pinned()); } -bool Session::pinnedCanPin(not_null thread) const { - if (const auto topic = thread->asTopic()) { +bool Session::pinnedCanPin(not_null entry) const { + if (const auto sublist = entry->asSublist()) { + const auto saved = &savedMessages(); + return pinnedChatsOrder(saved).size() < pinnedChatsLimit(saved); + } else if (const auto topic = entry->asTopic()) { const auto forum = topic->forum(); return pinnedChatsOrder(forum).size() < pinnedChatsLimit(forum); + } else { + const auto folder = entry->folder(); + return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder); } - const auto folder = thread->folder(); - return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder); } bool Session::pinnedCanPin( @@ -2240,7 +2244,7 @@ void Session::reorderTwoPinnedChats( ? topic->forum()->topicsList() : filterId ? chatsFilters().chatsList(filterId) - : chatsList(key1.entry()->folder()); + : chatsListFor(key1.entry()); list->pinned()->reorder(key1, key2); notifyPinnedDialogsOrderUpdated(); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index f1f31f1c2..244fa1524 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -349,7 +349,7 @@ public: const QVector &dialogs, std::optional count = std::nullopt); - [[nodiscard]] bool pinnedCanPin(not_null thread) const; + [[nodiscard]] bool pinnedCanPin(not_null entry) const; [[nodiscard]] bool pinnedCanPin( FilterId filterId, not_null history) const; diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp index af229100d..db3990963 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.cpp @@ -12,10 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "dialogs/dialogs_inner_widget.h" #include "history/view/history_view_sublist_section.h" +#include "info/media/info_media_buttons.h" +#include "info/profile/info_profile_icon.h" #include "info/info_controller.h" #include "info/info_memento.h" #include "main/main_session.h" #include "lang/lang_keys.h" +#include "ui/widgets/box_content_divider.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "styles/style_info.h" namespace Info::Saved { @@ -41,24 +47,27 @@ SublistsMemento::~SublistsMemento() = default; SublistsWidget::SublistsWidget( QWidget *parent, not_null controller) -: ContentWidget(parent, controller) { - _inner = setInnerWidget(object_ptr( +: ContentWidget(parent, controller) +, _layout(setInnerWidget(object_ptr(this))) { + setupOtherTypes(); + + _list = _layout->add(object_ptr( this, controller->parentController(), rpl::single(Dialogs::InnerWidget::ChildListShown()))); - _inner->showSavedSublists(); - _inner->setNarrowRatio(0.); + _list->showSavedSublists(); + _list->setNarrowRatio(0.); - _inner->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) { + _list->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) { if (const auto sublist = row.key.sublist()) { controller->showSection( std::make_shared(sublist), Window::SectionShow::Way::Forward); } - }, _inner->lifetime()); + }, _list->lifetime()); const auto saved = &controller->session().data().savedMessages(); - _inner->heightValue() | rpl::start_with_next([=] { + _list->heightValue() | rpl::start_with_next([=] { if (!saved->supported()) { crl::on_main(controller, [=] { controller->showSection( @@ -68,11 +77,61 @@ SublistsWidget::SublistsWidget( } }, lifetime()); - _inner->setLoadMoreCallback([=] { + _list->setLoadMoreCallback([=] { saved->loadMore(); }); } +void SublistsWidget::setupOtherTypes() { + auto wrap = _layout->add( + object_ptr>( + _layout, + object_ptr(_layout))); + auto content = wrap->entity(); + content->add(object_ptr( + content, + st::infoProfileSkip)); + + using Type = Media::Type; + auto tracker = Ui::MultiSlideTracker(); + const auto peer = controller()->session().user(); + const auto addMediaButton = [&]( + Type buttonType, + const style::icon &icon) { + auto result = Media::AddButton( + content, + controller(), + peer, + MsgId(), // topicRootId + nullptr, // migrated + buttonType, + tracker); + object_ptr( + result, + icon, + st::infoSharedMediaButtonIconPosition)->show(); + }; + + addMediaButton(Type::Photo, st::infoIconMediaPhoto); + addMediaButton(Type::Video, st::infoIconMediaVideo); + addMediaButton(Type::File, st::infoIconMediaFile); + addMediaButton(Type::MusicFile, st::infoIconMediaAudio); + addMediaButton(Type::Link, st::infoIconMediaLink); + addMediaButton(Type::RoundVoiceFile, st::infoIconMediaVoice); + addMediaButton(Type::GIF, st::infoIconMediaGif); + + content->add(object_ptr( + content, + st::infoProfileSkip)); + wrap->toggleOn(tracker.atLeastOneShownValue()); + wrap->finishAnimating(); + + _layout->add(object_ptr(_layout)); + _layout->add(object_ptr( + content, + st::infoProfileSkip)); +} + rpl::producer SublistsWidget::title() { return tr::lng_saved_messages(); } diff --git a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.h b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.h index b5d3cb0aa..64ada22ab 100644 --- a/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.h +++ b/Telegram/SourceFiles/info/saved/info_saved_sublists_widget.h @@ -17,6 +17,10 @@ namespace Main { class Session; } // namespace Main +namespace Ui { +class VerticalLayout; +} // namespace Ui + namespace Info::Saved { class SublistsMemento final : public ContentMemento { @@ -58,7 +62,10 @@ private: std::shared_ptr doCreateMemento() override; - Dialogs::InnerWidget *_inner = nullptr; + void setupOtherTypes(); + + const not_null _layout; + Dialogs::InnerWidget *_list = nullptr; }; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index fab799129..4b8ce6409 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -76,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum.h" #include "data/data_forum_topic.h" #include "data/data_user.h" +#include "data/data_saved_sublist.h" #include "data/data_scheduled_messages.h" #include "data/data_histories.h" #include "data/data_chat_filters.h" @@ -244,6 +245,7 @@ private: void fillRepliesActions(); void fillScheduledActions(); void fillArchiveActions(); + void fillSavedSublistActions(); void fillContextMenuActions(); void addHidePromotion(); @@ -293,6 +295,7 @@ private: Data::ForumTopic *_topic = nullptr; PeerData *_peer = nullptr; Data::Folder *_folder = nullptr; + Data::SavedSublist *_sublist = nullptr; const PeerMenuCallback &_addAction; }; @@ -319,17 +322,21 @@ void AddChatMembers( bool PinnedLimitReached( not_null controller, - not_null thread) { - const auto owner = &thread->owner(); - if (owner->pinnedCanPin(thread)) { + not_null entry) { + const auto owner = &entry->owner(); + if (owner->pinnedCanPin(entry)) { return false; } // Some old chat, that was converted, maybe is still pinned. - const auto history = thread->asHistory(); - if (!history) { - controller->show(Box(ForumPinsLimitBox, thread->asTopic()->forum())); + if (const auto sublist = entry->asSublist()) { + controller->show(Box(SublistsPinsLimitBox, &sublist->session())); + return true; + } else if (const auto topic = entry->asTopic()) { + controller->show(Box(ForumPinsLimitBox, topic->forum())); return true; } + const auto history = entry->asHistory(); + Assert(history != nullptr); const auto folder = history->folder(); const auto wasted = FindWastedPin(owner, folder); if (wasted) { @@ -359,18 +366,18 @@ bool PinnedLimitReached( void TogglePinnedThread( not_null controller, - not_null thread) { - if (!thread->folderKnown()) { + not_null entry) { + if (!entry->folderKnown()) { return; } - const auto owner = &thread->owner(); - const auto isPinned = !thread->isPinnedDialog(FilterId()); - if (isPinned && PinnedLimitReached(controller, thread)) { + const auto owner = &entry->owner(); + const auto isPinned = !entry->isPinnedDialog(FilterId()); + if (isPinned && PinnedLimitReached(controller, entry)) { return; } - owner->setChatPinned(thread, FilterId(), isPinned); - if (const auto history = thread->asHistory()) { + owner->setChatPinned(entry, FilterId(), isPinned); + if (const auto history = entry->asHistory()) { const auto flags = isPinned ? MTPmessages_ToggleDialogPin::Flag::f_pinned : MTPmessages_ToggleDialogPin::Flag(0); @@ -383,7 +390,7 @@ void TogglePinnedThread( if (isPinned) { controller->content()->dialogsToUp(); } - } else if (const auto topic = thread->asTopic()) { + } else if (const auto topic = entry->asTopic()) { owner->session().api().request(MTPchannels_UpdatePinnedForumTopic( topic->channel()->inputChannel, MTP_int(topic->rootId()), @@ -391,17 +398,30 @@ void TogglePinnedThread( )).done([=](const MTPUpdates &result) { owner->session().api().applyUpdates(result); }).send(); + } else if (const auto sublist = entry->asSublist()) { + const auto flags = isPinned + ? MTPmessages_ToggleSavedDialogPin::Flag::f_pinned + : MTPmessages_ToggleSavedDialogPin::Flag(0); + owner->session().api().request(MTPmessages_ToggleSavedDialogPin( + MTP_flags(flags), + MTP_inputDialogPeer(sublist->peer()->input) + )).done([=] { + owner->notifyPinnedDialogsOrderUpdated(); + }).send(); + //if (isPinned) { + // controller->content()->dialogsToUp(); + //} } } void TogglePinnedThread( not_null controller, - not_null thread, + not_null entry, FilterId filterId) { if (!filterId) { - return TogglePinnedThread(controller, thread); + return TogglePinnedThread(controller, entry); } - const auto history = thread->asHistory(); + const auto history = entry->asHistory(); if (!history) { return; } @@ -438,6 +458,7 @@ Filler::Filler( , _topic(request.key.topic()) , _peer(request.key.peer()) , _folder(request.key.folder()) +, _sublist(request.key.sublist()) , _addAction(addAction) { } @@ -471,21 +492,21 @@ void Filler::addToggleTopicClosed() { } void Filler::addTogglePin() { - if (!_peer || (_topic && !_topic->canTogglePinned())) { + if ((!_sublist && !_peer) || (_topic && !_topic->canTogglePinned())) { return; } const auto controller = _controller; const auto filterId = _request.filterId; - const auto thread = _request.key.thread(); - if (!thread || thread->fixedOnTopIndex()) { + const auto entry = _thread ? (Dialogs::Entry*)_thread : _sublist; + if (!entry || entry->fixedOnTopIndex()) { return; } const auto pinText = [=] { - return thread->isPinnedDialog(filterId) + return entry->isPinnedDialog(filterId) ? tr::lng_context_unpin_from_top(tr::now) : tr::lng_context_pin_to_top(tr::now); }; - const auto weak = base::make_weak(thread); + const auto weak = base::make_weak(entry); const auto pinToggle = [=] { if (const auto strong = weak.get()) { TogglePinnedThread(controller, strong, filterId); @@ -494,7 +515,7 @@ void Filler::addTogglePin() { _addAction( pinText(), pinToggle, - (thread->isPinnedDialog(filterId) + (entry->isPinnedDialog(filterId) ? &st::menuIconUnpin : &st::menuIconPin)); } @@ -1116,9 +1137,9 @@ void Filler::addGiftPremium() { void Filler::fill() { if (_folder) { fillArchiveActions(); - return; - } - switch (_request.section) { + } else if (_sublist) { + fillSavedSublistActions(); + } else switch (_request.section) { case Section::ChatsList: fillChatsListActions(); break; case Section::History: fillHistoryActions(); break; case Section::Profile: fillProfileActions(); break; @@ -1353,6 +1374,10 @@ void Filler::fillArchiveActions() { }, &st::menuIconManage); } +void Filler::fillSavedSublistActions() { + addTogglePin(); +} + } // namespace void PeerMenuExportChat(not_null peer) {