From adaa1d0c553d9076fdfb623ddf15d4d192eb6b5a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 19 Oct 2022 12:19:11 +0400 Subject: [PATCH] Support pinned topics in forums. --- Telegram/SourceFiles/api/api_updates.cpp | 18 ++++ Telegram/SourceFiles/data/data_forum.cpp | 7 ++ Telegram/SourceFiles/data/data_forum.h | 1 + .../SourceFiles/data/data_forum_topic.cpp | 9 +- Telegram/SourceFiles/data/data_forum_topic.h | 1 + Telegram/SourceFiles/data/data_session.cpp | 9 +- .../SourceFiles/window/window_peer_menu.cpp | 82 +++++++++++-------- 7 files changed, 86 insertions(+), 41 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index a2bf67394..57b42deec 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_drafts.h" #include "data/data_histories.h" #include "data/data_folder.h" +#include "data/data_forum.h" #include "data/data_scheduled_messages.h" #include "data/data_send_action.h" #include "data/data_message_reactions.h" @@ -2289,6 +2290,23 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateChannelPinnedTopic: { + const auto &d = update.c_updateChannelPinnedTopic(); + const auto peerId = peerFromChannel(d.vchannel_id()); + if (const auto peer = session().data().peerLoaded(peerId)) { + const auto rootId = d.vtopic_id().value_or_empty(); + if (const auto topic = peer->forumTopicFor(rootId)) { + session().data().setChatPinned(topic, 0, true); + } else if (const auto forum = peer->forum()) { + if (rootId) { + forum->requestTopic(rootId); + } else { + forum->unpinTopic(); + } + } + } + } break; + // Pinned message. case mtpc_updatePinnedMessages: { const auto &d = update.c_updatePinnedMessages(); diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 8a6ba9f3b..539285cd8 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -70,6 +70,13 @@ not_null Forum::topicsList() { return &_topicsList; } +void Forum::unpinTopic() { + const auto list = _topicsList.pinned(); + while (!list->order().empty()) { + list->setPinned(list->order().front(), false); + } +} + rpl::producer<> Forum::destroyed() const { return channel()->flagsValue( ) | rpl::filter([=](const ChannelData::Flags::Change &update) { diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index 1bc79e1ec..85062043f 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -41,6 +41,7 @@ public: void requestTopics(); [[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListLoadedEvents() const; + void unpinTopic(); void requestTopic(MsgId rootId, Fn done = nullptr); ForumTopic *applyTopicAdded( diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index d7d5d66fe..97b6514c6 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -206,6 +206,10 @@ bool ForumTopic::canToggleClosed() const { return !creating() && canEdit(); } +bool ForumTopic::canTogglePinned() const { + return !creating() && channel()->canEditTopics(); +} + bool ForumTopic::creating() const { return _forum->creating(_rootId); } @@ -238,11 +242,10 @@ void ForumTopic::applyTopic(const MTPDforumTopic &data) { } applyColorId(data.vicon_color().v); - const auto pinned = _list->pinned(); if (data.is_pinned()) { - pinned->addPinned(Dialogs::Key(this)); + owner().setChatPinned(this, 0, true); } else { - pinned->setPinned(Dialogs::Key(this), false); + _list->pinned()->setPinned(this, false); } owner().notifySettings().apply(this, data.vnotify_settings()); diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 7e9586cc8..003cbbdd2 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -63,6 +63,7 @@ public: [[nodiscard]] bool canEdit() const; [[nodiscard]] bool canToggleClosed() const; + [[nodiscard]] bool canTogglePinned() const; [[nodiscard]] bool closed() const; void setClosed(bool closed); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 064f5943e..712b84922 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1823,10 +1823,13 @@ void Session::setChatPinned( bool pinned) { Expects(key.entry()->folderKnown()); - const auto list = filterId + const auto list = (filterId ? chatsFilters().chatsList(filterId) - : chatsList(key.entry()->folder()); - list->pinned()->setPinned(key, pinned); + : chatsListFor(key.entry()))->pinned(); + if (const auto topic = key.topic()) { + topic->forum()->unpinTopic(); + } + list->setPinned(key, pinned); notifyPinnedDialogsOrderUpdated(); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 579b2f71e..b38d907d4 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -300,39 +300,55 @@ bool PinnedLimitReached( return true; } -void TogglePinnedDialog( +void TogglePinnedThread( not_null controller, - not_null history) { - if (!history->folderKnown()) { + not_null thread) { + if (!thread->folderKnown()) { return; } - const auto owner = &history->owner(); - const auto isPinned = !history->isPinnedDialog(0); - if (isPinned && PinnedLimitReached(controller, history, 0)) { - return; + const auto owner = &thread->owner(); + const auto isPinned = !thread->isPinnedDialog(0); + if (const auto history = thread->asHistory()) { + if (isPinned && PinnedLimitReached(controller, history, 0)) { + return; + } } - owner->setChatPinned(history, FilterId(), isPinned); - const auto flags = isPinned - ? MTPmessages_ToggleDialogPin::Flag::f_pinned - : MTPmessages_ToggleDialogPin::Flag(0); - history->session().api().request(MTPmessages_ToggleDialogPin( - MTP_flags(flags), - MTP_inputDialogPeer(history->peer->input) - )).done([=] { - owner->notifyPinnedDialogsOrderUpdated(); - }).send(); - if (isPinned) { - controller->content()->dialogsToUp(); + owner->setChatPinned(thread, FilterId(), isPinned); + if (const auto history = thread->asHistory()) { + const auto flags = isPinned + ? MTPmessages_ToggleDialogPin::Flag::f_pinned + : MTPmessages_ToggleDialogPin::Flag(0); + owner->session().api().request(MTPmessages_ToggleDialogPin( + MTP_flags(flags), + MTP_inputDialogPeer(history->peer->input) + )).done([=] { + owner->notifyPinnedDialogsOrderUpdated(); + }).send(); + if (isPinned) { + controller->content()->dialogsToUp(); + } + } else if (const auto topic = thread->asTopic()) { + owner->session().api().request(MTPchannels_UpdatePinnedForumTopic( + topic->channel()->inputChannel, + MTP_int(topic->rootId()), + MTP_bool(isPinned) + )).done([=](const MTPUpdates &result) { + owner->session().api().applyUpdates(result); + }).send(); } } -void TogglePinnedDialog( +void TogglePinnedThread( not_null controller, - not_null history, + not_null thread, FilterId filterId) { if (!filterId) { - return TogglePinnedDialog(controller, history); + return TogglePinnedThread(controller, thread); + } + const auto history = thread->asHistory(); + if (!history) { + return; } const auto owner = &history->owner(); @@ -402,37 +418,33 @@ void Filler::addToggleTopicClosed() { } void Filler::addTogglePin() { - if (!_peer || _topic) { - // #TODO forum pinned + if (!_peer || (_topic && !_topic->canTogglePinned())) { return; } const auto controller = _controller; const auto filterId = _request.filterId; const auto peer = _peer; - const auto history = _request.key.history(); - if (!history || history->fixedOnTopIndex()) { + const auto thread = _request.key.thread(); + if (!thread || thread->fixedOnTopIndex()) { return; } const auto pinText = [=] { - return history->isPinnedDialog(filterId) + return thread->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 pinToggle = [=] { - TogglePinnedDialog(controller, history, filterId); + if (const auto strong = weak.get()) { + TogglePinnedThread(controller, strong, filterId); + } }; const auto pinAction = _addAction( pinText(), pinToggle, - (history->isPinnedDialog(filterId) + (thread->isPinnedDialog(filterId) ? &st::menuIconUnpin : &st::menuIconPin)); - - auto actionText = history->session().changes().historyUpdates( - history, - Data::HistoryUpdate::Flag::IsPinned - ) | rpl::map(pinText); - SetActionText(pinAction, std::move(actionText)); } void Filler::addToggleMuteSubmenu(bool addSeparator) {