Support pinned saved sublists.

This commit is contained in:
John Preston 2023-12-31 08:49:55 +04:00
parent d2565dc944
commit 9392550c01
11 changed files with 301 additions and 82 deletions

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtproto_dc_options.h" #include "mtproto/mtproto_dc_options.h"
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "data/data_saved_messages.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_chat.h" #include "data/data_chat.h"
@ -2208,6 +2209,16 @@ void Updates::feedUpdate(const MTPUpdate &update) {
} }
} break; } 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: { case mtpc_updateChannel: {
auto &d = update.c_updateChannel(); auto &d = update.c_updateChannel();
if (const auto channel = session().data().channelLoaded(d.vchannel_id())) { if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {

View file

@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_saved_sublist.h"
#include "data/data_search_controller.h" #include "data/data_search_controller.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -443,8 +444,8 @@ void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) { void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
const auto &order = _session->data().pinnedChatsOrder(saved); const auto &order = _session->data().pinnedChatsOrder(saved);
const auto input = [](Dialogs::Key key) { const auto input = [](Dialogs::Key key) {
if (const auto history = key.history()) { if (const auto sublist = key.sublist()) {
return MTP_inputDialogPeer(history->peer->input); return MTP_inputDialogPeer(sublist->peer()->input);
} }
Unexpected("Key type in pinnedDialogsOrder()."); Unexpected("Key type in pinnedDialogsOrder().");
}; };

View file

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_saved_messages.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
@ -882,6 +883,18 @@ void PinsLimitBox(
limits.dialogsPinnedPremium(), limits.dialogsPinnedPremium(),
PinsCount(session->data().chatsList())); PinsCount(session->data().chatsList()));
} }
void SublistsPinsLimitBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) {
const auto limits = Data::PremiumLimits(session);
SimplePinsLimitBox(
box,
session,
"saved_dialog_pinned",
limits.savedSublistsPinnedDefault(),
limits.savedSublistsPinnedPremium(),
PinsCount(session->data().savedMessages().chatsList()));
}
void ForumPinsLimitBox( void ForumPinsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,

View file

@ -60,6 +60,9 @@ void PinsLimitBox(
void ForumPinsLimitBox( void ForumPinsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Data::Forum*> forum); not_null<Data::Forum*> forum);
void SublistsPinsLimitBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session);
void CaptionLimitBox( void CaptionLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session, not_null<Main::Session*> session,

View file

@ -62,54 +62,19 @@ not_null<SavedSublist*> SavedMessages::sublist(not_null<PeerData*> peer) {
void SavedMessages::loadMore() { void SavedMessages::loadMore() {
if (_loadMoreRequestId || _chatsList.loaded()) { if (_loadMoreRequestId || _chatsList.loaded()) {
return; return;
} else if (!_pinnedLoaded) {
loadPinned();
} }
_loadMoreRequestId = _owner->session().api().request( _loadMoreRequestId = _owner->session().api().request(
MTPmessages_GetSavedDialogs( MTPmessages_GetSavedDialogs(
MTP_flags(0), MTP_flags(MTPmessages_GetSavedDialogs::Flag::f_exclude_pinned),
MTP_int(_offsetDate), MTP_int(_offsetDate),
MTP_int(_offsetId), MTP_int(_offsetId),
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(), _offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
MTP_int(kPerPage), MTP_int(kPerPage),
MTP_long(0)) // hash MTP_long(0)) // hash
).done([=](const MTPmessages_SavedDialogs &result) { ).done([=](const MTPmessages_SavedDialogs &result) {
auto list = (const QVector<MTPSavedDialog>*)nullptr; apply(result, false);
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();
}
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) { if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
_unsupported = true; _unsupported = true;
@ -119,6 +84,24 @@ void SavedMessages::loadMore() {
}).send(); }).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<SavedSublist*> sublist) { void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) { if (_loadMoreRequests.contains(sublist) || sublist->isFullLoaded()) {
return; return;
@ -185,4 +168,109 @@ void SavedMessages::loadMore(not_null<SavedSublist*> sublist) {
_loadMoreRequests[sublist] = requestId; _loadMoreRequests[sublist] = requestId;
} }
void SavedMessages::apply(
const MTPmessages_SavedDialogs &result,
bool pinned) {
auto list = (const QVector<MTPSavedDialog>*)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 } // namespace Data

View file

@ -34,7 +34,13 @@ public:
void loadMore(); void loadMore();
void loadMore(not_null<SavedSublist*> sublist); void loadMore(not_null<SavedSublist*> sublist);
void apply(const MTPDupdatePinnedSavedDialogs &update);
void apply(const MTPDupdateSavedDialogPinned &update);
private: private:
void loadPinned();
void apply(const MTPmessages_SavedDialogs &result, bool pinned);
const not_null<Session*> _owner; const not_null<Session*> _owner;
Dialogs::MainList _chatsList; Dialogs::MainList _chatsList;
@ -44,11 +50,13 @@ private:
base::flat_map<not_null<SavedSublist*>, mtpRequestId> _loadMoreRequests; base::flat_map<not_null<SavedSublist*>, mtpRequestId> _loadMoreRequests;
mtpRequestId _loadMoreRequestId = 0; mtpRequestId _loadMoreRequestId = 0;
mtpRequestId _pinnedRequestId = 0;
TimeId _offsetDate = 0; TimeId _offsetDate = 0;
MsgId _offsetId = 0; MsgId _offsetId = 0;
PeerData *_offsetPeer = nullptr; PeerData *_offsetPeer = nullptr;
bool _pinnedLoaded = false;
bool _unsupported = false; bool _unsupported = false;
}; };

View file

@ -2107,13 +2107,17 @@ void Session::applyDialog(
setPinnedFromEntryList(folder, data.is_pinned()); setPinnedFromEntryList(folder, data.is_pinned());
} }
bool Session::pinnedCanPin(not_null<Data::Thread*> thread) const { bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
if (const auto topic = thread->asTopic()) { 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(); const auto forum = topic->forum();
return pinnedChatsOrder(forum).size() < pinnedChatsLimit(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( bool Session::pinnedCanPin(
@ -2240,7 +2244,7 @@ void Session::reorderTwoPinnedChats(
? topic->forum()->topicsList() ? topic->forum()->topicsList()
: filterId : filterId
? chatsFilters().chatsList(filterId) ? chatsFilters().chatsList(filterId)
: chatsList(key1.entry()->folder()); : chatsListFor(key1.entry());
list->pinned()->reorder(key1, key2); list->pinned()->reorder(key1, key2);
notifyPinnedDialogsOrderUpdated(); notifyPinnedDialogsOrderUpdated();
} }

View file

@ -349,7 +349,7 @@ public:
const QVector<MTPDialog> &dialogs, const QVector<MTPDialog> &dialogs,
std::optional<int> count = std::nullopt); std::optional<int> count = std::nullopt);
[[nodiscard]] bool pinnedCanPin(not_null<Thread*> thread) const; [[nodiscard]] bool pinnedCanPin(not_null<Dialogs::Entry*> entry) const;
[[nodiscard]] bool pinnedCanPin( [[nodiscard]] bool pinnedCanPin(
FilterId filterId, FilterId filterId,
not_null<History*> history) const; not_null<History*> history) const;

View file

@ -12,10 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "dialogs/dialogs_inner_widget.h" #include "dialogs/dialogs_inner_widget.h"
#include "history/view/history_view_sublist_section.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_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "lang/lang_keys.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 { namespace Info::Saved {
@ -41,24 +47,27 @@ SublistsMemento::~SublistsMemento() = default;
SublistsWidget::SublistsWidget( SublistsWidget::SublistsWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller) not_null<Controller*> controller)
: ContentWidget(parent, controller) { : ContentWidget(parent, controller)
_inner = setInnerWidget(object_ptr<Dialogs::InnerWidget>( , _layout(setInnerWidget(object_ptr<Ui::VerticalLayout>(this))) {
setupOtherTypes();
_list = _layout->add(object_ptr<Dialogs::InnerWidget>(
this, this,
controller->parentController(), controller->parentController(),
rpl::single(Dialogs::InnerWidget::ChildListShown()))); rpl::single(Dialogs::InnerWidget::ChildListShown())));
_inner->showSavedSublists(); _list->showSavedSublists();
_inner->setNarrowRatio(0.); _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()) { if (const auto sublist = row.key.sublist()) {
controller->showSection( controller->showSection(
std::make_shared<HistoryView::SublistMemento>(sublist), std::make_shared<HistoryView::SublistMemento>(sublist),
Window::SectionShow::Way::Forward); Window::SectionShow::Way::Forward);
} }
}, _inner->lifetime()); }, _list->lifetime());
const auto saved = &controller->session().data().savedMessages(); const auto saved = &controller->session().data().savedMessages();
_inner->heightValue() | rpl::start_with_next([=] { _list->heightValue() | rpl::start_with_next([=] {
if (!saved->supported()) { if (!saved->supported()) {
crl::on_main(controller, [=] { crl::on_main(controller, [=] {
controller->showSection( controller->showSection(
@ -68,11 +77,61 @@ SublistsWidget::SublistsWidget(
} }
}, lifetime()); }, lifetime());
_inner->setLoadMoreCallback([=] { _list->setLoadMoreCallback([=] {
saved->loadMore(); saved->loadMore();
}); });
} }
void SublistsWidget::setupOtherTypes() {
auto wrap = _layout->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
_layout,
object_ptr<Ui::VerticalLayout>(_layout)));
auto content = wrap->entity();
content->add(object_ptr<Ui::FixedHeightWidget>(
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<Profile::FloatingIcon>(
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<Ui::FixedHeightWidget>(
content,
st::infoProfileSkip));
wrap->toggleOn(tracker.atLeastOneShownValue());
wrap->finishAnimating();
_layout->add(object_ptr<Ui::BoxContentDivider>(_layout));
_layout->add(object_ptr<Ui::FixedHeightWidget>(
content,
st::infoProfileSkip));
}
rpl::producer<QString> SublistsWidget::title() { rpl::producer<QString> SublistsWidget::title() {
return tr::lng_saved_messages(); return tr::lng_saved_messages();
} }

View file

@ -17,6 +17,10 @@ namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
namespace Ui {
class VerticalLayout;
} // namespace Ui
namespace Info::Saved { namespace Info::Saved {
class SublistsMemento final : public ContentMemento { class SublistsMemento final : public ContentMemento {
@ -58,7 +62,10 @@ private:
std::shared_ptr<ContentMemento> doCreateMemento() override; std::shared_ptr<ContentMemento> doCreateMemento() override;
Dialogs::InnerWidget *_inner = nullptr; void setupOtherTypes();
const not_null<Ui::VerticalLayout*> _layout;
Dialogs::InnerWidget *_list = nullptr;
}; };

View file

@ -76,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_forum_topic.h" #include "data/data_forum_topic.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_saved_sublist.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_chat_filters.h" #include "data/data_chat_filters.h"
@ -244,6 +245,7 @@ private:
void fillRepliesActions(); void fillRepliesActions();
void fillScheduledActions(); void fillScheduledActions();
void fillArchiveActions(); void fillArchiveActions();
void fillSavedSublistActions();
void fillContextMenuActions(); void fillContextMenuActions();
void addHidePromotion(); void addHidePromotion();
@ -293,6 +295,7 @@ private:
Data::ForumTopic *_topic = nullptr; Data::ForumTopic *_topic = nullptr;
PeerData *_peer = nullptr; PeerData *_peer = nullptr;
Data::Folder *_folder = nullptr; Data::Folder *_folder = nullptr;
Data::SavedSublist *_sublist = nullptr;
const PeerMenuCallback &_addAction; const PeerMenuCallback &_addAction;
}; };
@ -319,17 +322,21 @@ void AddChatMembers(
bool PinnedLimitReached( bool PinnedLimitReached(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Data::Thread*> thread) { not_null<Dialogs::Entry*> entry) {
const auto owner = &thread->owner(); const auto owner = &entry->owner();
if (owner->pinnedCanPin(thread)) { if (owner->pinnedCanPin(entry)) {
return false; return false;
} }
// Some old chat, that was converted, maybe is still pinned. // Some old chat, that was converted, maybe is still pinned.
const auto history = thread->asHistory(); if (const auto sublist = entry->asSublist()) {
if (!history) { controller->show(Box(SublistsPinsLimitBox, &sublist->session()));
controller->show(Box(ForumPinsLimitBox, thread->asTopic()->forum())); return true;
} else if (const auto topic = entry->asTopic()) {
controller->show(Box(ForumPinsLimitBox, topic->forum()));
return true; return true;
} }
const auto history = entry->asHistory();
Assert(history != nullptr);
const auto folder = history->folder(); const auto folder = history->folder();
const auto wasted = FindWastedPin(owner, folder); const auto wasted = FindWastedPin(owner, folder);
if (wasted) { if (wasted) {
@ -359,18 +366,18 @@ bool PinnedLimitReached(
void TogglePinnedThread( void TogglePinnedThread(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Data::Thread*> thread) { not_null<Dialogs::Entry*> entry) {
if (!thread->folderKnown()) { if (!entry->folderKnown()) {
return; return;
} }
const auto owner = &thread->owner(); const auto owner = &entry->owner();
const auto isPinned = !thread->isPinnedDialog(FilterId()); const auto isPinned = !entry->isPinnedDialog(FilterId());
if (isPinned && PinnedLimitReached(controller, thread)) { if (isPinned && PinnedLimitReached(controller, entry)) {
return; return;
} }
owner->setChatPinned(thread, FilterId(), isPinned); owner->setChatPinned(entry, FilterId(), isPinned);
if (const auto history = thread->asHistory()) { if (const auto history = entry->asHistory()) {
const auto flags = isPinned const auto flags = isPinned
? MTPmessages_ToggleDialogPin::Flag::f_pinned ? MTPmessages_ToggleDialogPin::Flag::f_pinned
: MTPmessages_ToggleDialogPin::Flag(0); : MTPmessages_ToggleDialogPin::Flag(0);
@ -383,7 +390,7 @@ void TogglePinnedThread(
if (isPinned) { if (isPinned) {
controller->content()->dialogsToUp(); controller->content()->dialogsToUp();
} }
} else if (const auto topic = thread->asTopic()) { } else if (const auto topic = entry->asTopic()) {
owner->session().api().request(MTPchannels_UpdatePinnedForumTopic( owner->session().api().request(MTPchannels_UpdatePinnedForumTopic(
topic->channel()->inputChannel, topic->channel()->inputChannel,
MTP_int(topic->rootId()), MTP_int(topic->rootId()),
@ -391,17 +398,30 @@ void TogglePinnedThread(
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
owner->session().api().applyUpdates(result); owner->session().api().applyUpdates(result);
}).send(); }).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( void TogglePinnedThread(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Data::Thread*> thread, not_null<Dialogs::Entry*> entry,
FilterId filterId) { FilterId filterId) {
if (!filterId) { if (!filterId) {
return TogglePinnedThread(controller, thread); return TogglePinnedThread(controller, entry);
} }
const auto history = thread->asHistory(); const auto history = entry->asHistory();
if (!history) { if (!history) {
return; return;
} }
@ -438,6 +458,7 @@ Filler::Filler(
, _topic(request.key.topic()) , _topic(request.key.topic())
, _peer(request.key.peer()) , _peer(request.key.peer())
, _folder(request.key.folder()) , _folder(request.key.folder())
, _sublist(request.key.sublist())
, _addAction(addAction) { , _addAction(addAction) {
} }
@ -471,21 +492,21 @@ void Filler::addToggleTopicClosed() {
} }
void Filler::addTogglePin() { void Filler::addTogglePin() {
if (!_peer || (_topic && !_topic->canTogglePinned())) { if ((!_sublist && !_peer) || (_topic && !_topic->canTogglePinned())) {
return; return;
} }
const auto controller = _controller; const auto controller = _controller;
const auto filterId = _request.filterId; const auto filterId = _request.filterId;
const auto thread = _request.key.thread(); const auto entry = _thread ? (Dialogs::Entry*)_thread : _sublist;
if (!thread || thread->fixedOnTopIndex()) { if (!entry || entry->fixedOnTopIndex()) {
return; return;
} }
const auto pinText = [=] { const auto pinText = [=] {
return thread->isPinnedDialog(filterId) return entry->isPinnedDialog(filterId)
? tr::lng_context_unpin_from_top(tr::now) ? tr::lng_context_unpin_from_top(tr::now)
: tr::lng_context_pin_to_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 = [=] { const auto pinToggle = [=] {
if (const auto strong = weak.get()) { if (const auto strong = weak.get()) {
TogglePinnedThread(controller, strong, filterId); TogglePinnedThread(controller, strong, filterId);
@ -494,7 +515,7 @@ void Filler::addTogglePin() {
_addAction( _addAction(
pinText(), pinText(),
pinToggle, pinToggle,
(thread->isPinnedDialog(filterId) (entry->isPinnedDialog(filterId)
? &st::menuIconUnpin ? &st::menuIconUnpin
: &st::menuIconPin)); : &st::menuIconPin));
} }
@ -1116,9 +1137,9 @@ void Filler::addGiftPremium() {
void Filler::fill() { void Filler::fill() {
if (_folder) { if (_folder) {
fillArchiveActions(); fillArchiveActions();
return; } else if (_sublist) {
} fillSavedSublistActions();
switch (_request.section) { } else switch (_request.section) {
case Section::ChatsList: fillChatsListActions(); break; case Section::ChatsList: fillChatsListActions(); break;
case Section::History: fillHistoryActions(); break; case Section::History: fillHistoryActions(); break;
case Section::Profile: fillProfileActions(); break; case Section::Profile: fillProfileActions(); break;
@ -1353,6 +1374,10 @@ void Filler::fillArchiveActions() {
}, &st::menuIconManage); }, &st::menuIconManage);
} }
void Filler::fillSavedSublistActions() {
addTogglePin();
}
} // namespace } // namespace
void PeerMenuExportChat(not_null<PeerData*> peer) { void PeerMenuExportChat(not_null<PeerData*> peer) {