Support pinned topics in forums.

This commit is contained in:
John Preston 2022-10-19 12:19:11 +04:00
parent 306179ca7c
commit adaa1d0c55
7 changed files with 86 additions and 41 deletions

View File

@ -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();

View File

@ -70,6 +70,13 @@ not_null<Dialogs::MainList*> 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) {

View File

@ -41,6 +41,7 @@ public:
void requestTopics();
[[nodiscard]] rpl::producer<> chatsListChanges() const;
[[nodiscard]] rpl::producer<> chatsListLoadedEvents() const;
void unpinTopic();
void requestTopic(MsgId rootId, Fn<void()> done = nullptr);
ForumTopic *applyTopicAdded(

View File

@ -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());

View File

@ -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);

View File

@ -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();
}

View File

@ -300,39 +300,55 @@ bool PinnedLimitReached(
return true;
}
void TogglePinnedDialog(
void TogglePinnedThread(
not_null<Window::SessionController*> controller,
not_null<History*> history) {
if (!history->folderKnown()) {
not_null<Data::Thread*> 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<Window::SessionController*> controller,
not_null<History*> history,
not_null<Data::Thread*> 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) {