Create / move forum topics on new messages.

This commit is contained in:
John Preston 2022-09-23 23:21:31 +04:00
parent 388fe6adfb
commit eaf679916a
19 changed files with 155 additions and 58 deletions

View file

@ -1453,7 +1453,7 @@ stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword
forumTopic#4a0005d9 flags:# pinned:flags.2?true id:int date:int title:string top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int = ForumTopic; forumTopic#4a0005d9 flags:# pinned:flags.2?true id:int date:int title:string top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int = ForumTopic;
messages.forumTopics#ed93d3e flags:# count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int next_date:flags.0?int = messages.ForumTopics; messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int = messages.ForumTopics;
---functions--- ---functions---
@ -1856,6 +1856,7 @@ channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates; channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates;
channels.createForumTopic#22cf4868 flags:# no_webpage:flags.3?true channel:InputChannel title:string media:flags.0?InputMedia message:string random_id:long entities:flags.1?Vector<MessageEntity> send_as:flags.2?InputPeer = Updates; channels.createForumTopic#22cf4868 flags:# no_webpage:flags.3?true channel:InputChannel title:string media:flags.0?InputMedia message:string random_id:long entities:flags.1?Vector<MessageEntity> send_as:flags.2?InputPeer = Updates;
channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector<int> = messages.ForumTopics;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;

View file

@ -13,10 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat_participant_status.h" #include "data/data_chat_participant_status.h"
#include "data/data_peer_bot_commands.h" #include "data/data_peer_bot_commands.h"
namespace Data {
class Forum;
} // namespace Data
struct ChannelLocation { struct ChannelLocation {
QString address; QString address;
Data::LocationPoint point; Data::LocationPoint point;

View file

@ -69,23 +69,27 @@ void Forum::requestTopics() {
const auto &list = data.vtopics().v; const auto &list = data.vtopics().v;
for (const auto &topic : list) { for (const auto &topic : list) {
const auto rootId = MsgId(topic.data().vid().v); const auto rootId = MsgId(topic.data().vid().v);
if (const auto i = _topics.find(rootId); i != end(_topics)) { const auto i = _topics.find(rootId);
i->second->applyTopic(topic); const auto creating = (i == end(_topics));
} else { const auto raw = creating
const auto raw = _topics.emplace( ? _topics.emplace(
rootId, rootId,
std::make_unique<ForumTopic>(forum, rootId) std::make_unique<ForumTopic>(forum, rootId)
).first->second.get(); ).first->second.get()
raw->applyTopic(topic); : i->second.get();
raw->applyTopic(topic);
if (creating) {
raw->addToChatList(FilterId(), topicsList()); raw->addToChatList(FilterId(), topicsList());
} }
if (const auto last = raw->lastServerMessage()) {
_offsetDate = last->date();
_offsetId = last->id;
}
_offsetTopicId = rootId;
} }
if (list.isEmpty() || list.size() == data.vcount().v) { if (list.isEmpty() || list.size() == data.vcount().v) {
_allLoaded = true; _allLoaded = true;
} }
if (const auto date = data.vnext_date()) {
_offsetDate = date->v;
}
_requestId = 0; _requestId = 0;
_chatsListChanges.fire({}); _chatsListChanges.fire({});
if (_allLoaded) { if (_allLoaded) {
@ -97,21 +101,35 @@ void Forum::requestTopics() {
}).send(); }).send();
} }
void Forum::topicAdded(not_null<HistoryItem*> root) { void Forum::applyTopicAdded(MsgId rootId, const QString &title) {
const auto rootId = root->id;
if (const auto i = _topics.find(rootId); i != end(_topics)) { if (const auto i = _topics.find(rootId); i != end(_topics)) {
//i->second->applyTopic(topic); i->second->applyTitle(title);
} else { } else {
const auto raw = _topics.emplace( const auto raw = _topics.emplace(
rootId, rootId,
std::make_unique<ForumTopic>(_forum, rootId) std::make_unique<ForumTopic>(_forum, rootId)
).first->second.get(); ).first->second.get();
//raw->applyTopic(topic); raw->applyTitle(title);
raw->addToChatList(FilterId(), topicsList()); raw->addToChatList(FilterId(), topicsList());
_chatsListChanges.fire({}); _chatsListChanges.fire({});
} }
} }
void Forum::applyTopicRemoved(MsgId rootId) {
//if (const auto i = _topics.find(rootId)) {
// _topics.erase(i);
//}
}
ForumTopic *Forum::topicFor(not_null<HistoryItem*> item) {
if (const auto rootId = item->replyToTop()) {
if (const auto i = _topics.find(rootId); i != end(_topics)) {
return i->second.get();
}
}
return nullptr;
}
rpl::producer<> Forum::chatsListChanges() const { rpl::producer<> Forum::chatsListChanges() const {
return _chatsListChanges.events(); return _chatsListChanges.events();
} }

View file

@ -29,7 +29,9 @@ public:
[[nodiscard]] rpl::producer<> chatsListChanges() const; [[nodiscard]] rpl::producer<> chatsListChanges() const;
[[nodiscard]] rpl::producer<> chatsListLoadedEvents() const; [[nodiscard]] rpl::producer<> chatsListLoadedEvents() const;
void topicAdded(not_null<HistoryItem*> root); void applyTopicAdded(MsgId rootId, const QString &title);
void applyTopicRemoved(MsgId rootId);
[[nodiscard]] ForumTopic *topicFor(not_null<HistoryItem*> item);
private: private:
const not_null<History*> _forum; const not_null<History*> _forum;

View file

@ -37,13 +37,7 @@ void ForumTopic::applyTopic(const MTPForumTopic &topic) {
Expects(_rootId == topic.data().vid().v); Expects(_rootId == topic.data().vid().v);
const auto &data = topic.data(); const auto &data = topic.data();
const auto title = qs(data.vtitle()); applyTitle(qs(data.vtitle()));
if (_title != title) {
_title = title;
++_titleVersion;
indexTitleParts();
updateChatListEntry();
}
const auto pinned = _list->pinned(); const auto pinned = _list->pinned();
if (data.is_pinned()) { if (data.is_pinned()) {
@ -216,7 +210,7 @@ TimeId ForumTopic::adjustedChatListTimeId() const {
} }
int ForumTopic::fixedOnTopIndex() const { int ForumTopic::fixedOnTopIndex() const {
return kArchiveFixOnTopIndex; return 0;
} }
bool ForumTopic::shouldBeInChatList() const { bool ForumTopic::shouldBeInChatList() const {
@ -241,6 +235,38 @@ bool ForumTopic::lastServerMessageKnown() const {
return _lastServerMessage.has_value(); return _lastServerMessage.has_value();
} }
void ForumTopic::applyTitle(const QString &title) {
if (_title == title) {
return;
}
_title = title;
++_titleVersion;
indexTitleParts();
updateChatListEntry();
}
void ForumTopic::applyItemAdded(not_null<HistoryItem*> item) {
setLastMessage(item);
}
void ForumTopic::applyItemRemoved(MsgId id) {
if (const auto lastItem = lastMessage()) {
if (lastItem->id == id) {
_lastMessage = std::nullopt;
}
}
if (const auto lastServerItem = lastServerMessage()) {
if (lastServerItem->id == id) {
_lastServerMessage = std::nullopt;
}
}
if (const auto chatListItem = _chatListMessage.value_or(nullptr)) {
if (chatListItem->id == id) {
_chatListMessage = std::nullopt;
}
}
}
int ForumTopic::unreadCount() const { int ForumTopic::unreadCount() const {
return _unreadCount ? *_unreadCount : 0; return _unreadCount ? *_unreadCount : 0;
} }

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "dialogs/dialogs_entry.h" #include "dialogs/dialogs_entry.h"
#include "dialogs/ui/dialogs_message_view.h"
class ChannelData; class ChannelData;
@ -56,6 +57,10 @@ public:
[[nodiscard]] bool lastMessageKnown() const; [[nodiscard]] bool lastMessageKnown() const;
[[nodiscard]] bool lastServerMessageKnown() const; [[nodiscard]] bool lastServerMessageKnown() const;
void applyTitle(const QString &title);
void applyItemAdded(not_null<HistoryItem*> item);
void applyItemRemoved(MsgId id);
void loadUserpic() override; void loadUserpic() override;
void paintUserpic( void paintUserpic(
Painter &p, Painter &p,
@ -73,6 +78,9 @@ public:
void setUnreadMark(bool unread); void setUnreadMark(bool unread);
[[nodiscard]] bool unreadMark() const; [[nodiscard]] bool unreadMark() const;
Ui::Text::String cloudDraftTextCache;
Dialogs::Ui::MessageView lastItemDialogsView;
private: private:
void indexTitleParts(); void indexTitleParts();
void applyTopicTopMessage(MsgId topMessageId); void applyTopicTopMessage(MsgId topMessageId);

View file

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_message_view.h" #include "dialogs/ui/dialogs_message_view.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
namespace Data { namespace Data {
namespace { namespace {
@ -145,6 +147,11 @@ void Groups::refreshViews(const HistoryItemsList &items) {
for (const auto &item : items) { for (const auto &item : items) {
_data->requestItemViewRefresh(item); _data->requestItemViewRefresh(item);
history->lastItemDialogsView.itemInvalidated(item); history->lastItemDialogsView.itemInvalidated(item);
if (const auto forum = history->peer->forum()) {
if (const auto topic = forum->topicFor(item)) {
topic->lastItemDialogsView.itemInvalidated(item);
}
}
} }
} }

View file

@ -882,6 +882,13 @@ bool PeerData::isRepliesChat() const {
: kTestId) == id; : kTestId) == id;
} }
Data::Forum *PeerData::forum() const {
if (const auto channel = asChannel()) {
return channel->forum();
}
return nullptr;
}
bool PeerData::canWrite() const { bool PeerData::canWrite() const {
if (const auto user = asUser()) { if (const auto user = asUser()) {
return user->canWrite(); return user->canWrite();

View file

@ -32,6 +32,7 @@ class Session;
namespace Data { namespace Data {
class Forum;
class Session; class Session;
class GroupCall; class GroupCall;
class CloudImageView; class CloudImageView;
@ -195,6 +196,8 @@ public:
return isUser() && !(id.value % 1000); return isUser() && !(id.value % 1000);
} }
[[nodiscard]] Data::Forum *forum() const;
[[nodiscard]] std::optional<TimeId> notifyMuteUntil() const { [[nodiscard]] std::optional<TimeId> notifyMuteUntil() const {
return _notify.muteUntil(); return _notify.muteUntil();
} }

View file

@ -67,6 +67,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "base/unixtime.h" #include "base/unixtime.h"
@ -3793,7 +3795,9 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
const auto entry = key.entry(); const auto entry = key.entry();
const auto history = key.history(); const auto history = key.history();
const auto mainList = chatsList(entry->folder()); const auto mainList = entry->asTopic()
? entry->asTopic()->forum()->peer->forum()->topicsList()
: chatsList(entry->folder());
auto event = ChatListEntryRefresh{ .key = key }; auto event = ChatListEntryRefresh{ .key = key };
const auto creating = event.existenceChanged = !entry->inChatList(); const auto creating = event.existenceChanged = !entry->inChatList();
if (event.existenceChanged) { if (event.existenceChanged) {
@ -3848,6 +3852,7 @@ void Session::removeChatListEntry(Dialogs::Key key) {
return; return;
} }
Assert(entry->folderKnown()); Assert(entry->folderKnown());
for (const auto &filter : _chatsFilters->list()) { for (const auto &filter : _chatsFilters->list()) {
const auto id = filter.id(); const auto id = filter.id();
if (id && entry->inChatList(id)) { if (id && entry->inChatList(id)) {
@ -3859,7 +3864,9 @@ void Session::removeChatListEntry(Dialogs::Key key) {
}); });
} }
} }
const auto mainList = chatsList(entry->folder()); const auto mainList = entry->asTopic()
? entry->asTopic()->forum()->peer->forum()->topicsList()
: chatsList(entry->folder());
entry->removeFromChatList(0, mainList); entry->removeFromChatList(0, mainList);
_chatListEntryRefreshes.fire(ChatListEntryRefresh{ _chatListEntryRefreshes.fire(ChatListEntryRefresh{
.key = key, .key = key,

View file

@ -67,7 +67,7 @@ Data::Folder *Entry::asFolder() {
: nullptr; : nullptr;
} }
Data::ForumTopic *Entry::asForumTopic() { Data::ForumTopic *Entry::asTopic() {
return (_type == Type::ForumTopic) return (_type == Type::ForumTopic)
? static_cast<Data::ForumTopic*>(this) ? static_cast<Data::ForumTopic*>(this)
: nullptr; : nullptr;
@ -186,9 +186,6 @@ const Ui::Text::String &Entry::chatListNameText() const {
} }
void Entry::setChatListExistence(bool exists) { void Entry::setChatListExistence(bool exists) {
if (asForumTopic()) {
return;
}
if (exists && _sortKeyInChatList) { if (exists && _sortKeyInChatList) {
owner().refreshChatListEntry(this); owner().refreshChatListEntry(this);
updateChatListEntry(); updateChatListEntry();
@ -263,7 +260,7 @@ not_null<Row*> Entry::addToChatList(
void Entry::removeFromChatList( void Entry::removeFromChatList(
FilterId filterId, FilterId filterId,
not_null<MainList*> list) { not_null<MainList*> list) {
if (!asForumTopic() && isPinnedDialog(filterId)) { if (!asTopic() && isPinnedDialog(filterId)) {
owner().setChatPinned(this, filterId, false); owner().setChatPinned(this, filterId, false);
} }

View file

@ -107,7 +107,7 @@ public:
History *asHistory(); History *asHistory();
Data::Folder *asFolder(); Data::Folder *asFolder();
Data::ForumTopic *asForumTopic(); Data::ForumTopic *asTopic();
PositionChange adjustByPosInChatList( PositionChange adjustByPosInChatList(
FilterId filterId, FilterId filterId,

View file

@ -25,7 +25,7 @@ Key::Key(History *history) : _value(history) {
Key::Key(Data::Folder *folder) : _value(folder) { Key::Key(Data::Folder *folder) : _value(folder) {
} }
Key::Key(Data::ForumTopic *forumTopic) : _value(forumTopic) { Key::Key(Data::ForumTopic *topic) : _value(topic) {
} }
Key::Key(not_null<History*> history) : _value(history) { Key::Key(not_null<History*> history) : _value(history) {
@ -34,7 +34,7 @@ Key::Key(not_null<History*> history) : _value(history) {
Key::Key(not_null<Data::Folder*> folder) : _value(folder) { Key::Key(not_null<Data::Folder*> folder) : _value(folder) {
} }
Key::Key(not_null<Data::ForumTopic*> forumTopic) : _value(forumTopic) { Key::Key(not_null<Data::ForumTopic*> topic) : _value(topic) {
} }
not_null<Entry*> Key::entry() const { not_null<Entry*> Key::entry() const {
@ -51,8 +51,8 @@ Folder *Key::folder() const {
return _value ? _value->asFolder() : nullptr; return _value ? _value->asFolder() : nullptr;
} }
ForumTopic *Key::forumTopic() const { ForumTopic *Key::topic() const {
return _value ? _value->asForumTopic() : nullptr; return _value ? _value->asTopic() : nullptr;
} }
PeerData *Key::peer() const { PeerData *Key::peer() const {

View file

@ -28,12 +28,12 @@ public:
} }
Key(History *history); Key(History *history);
Key(Data::Folder *folder); Key(Data::Folder *folder);
Key(Data::ForumTopic *forumTopic); Key(Data::ForumTopic *topic);
Key(not_null<Entry*> entry) : _value(entry) { Key(not_null<Entry*> entry) : _value(entry) {
} }
Key(not_null<History*> history); Key(not_null<History*> history);
Key(not_null<Data::Folder*> folder); Key(not_null<Data::Folder*> folder);
Key(not_null<Data::ForumTopic*> forumTopic); Key(not_null<Data::ForumTopic*> topic);
explicit operator bool() const { explicit operator bool() const {
return (_value != nullptr); return (_value != nullptr);
@ -41,7 +41,7 @@ public:
not_null<Entry*> entry() const; not_null<Entry*> entry() const;
History *history() const; History *history() const;
Data::Folder *folder() const; Data::Folder *folder() const;
Data::ForumTopic *forumTopic() const; Data::ForumTopic *topic() const;
PeerData *peer() const; PeerData *peer() const;
inline bool operator<(const Key &other) const { inline bool operator<(const Key &other) const {

View file

@ -98,6 +98,9 @@ public:
[[nodiscard]] Data::Folder *folder() const { [[nodiscard]] Data::Folder *folder() const {
return _id.folder(); return _id.folder();
} }
[[nodiscard]] Data::ForumTopic *topic() const {
return _id.topic();
}
[[nodiscard]] not_null<Entry*> entry() const { [[nodiscard]] not_null<Entry*> entry() const {
return _id.entry(); return _id.entry();
} }

View file

@ -263,10 +263,10 @@ Widget::Widget(
const auto openSearchResult = !controller->selectingPeer() const auto openSearchResult = !controller->selectingPeer()
&& row.filteredRow; && row.filteredRow;
const auto history = row.key.history(); const auto history = row.key.history();
if (const auto forumTopic = row.key.forumTopic()) { if (const auto topic = row.key.topic()) {
controller->showRepliesForMessage( controller->showRepliesForMessage(
forumTopic->forum(), topic->forum(),
forumTopic->rootId()); topic->rootId());
} else if (history && history->peer->isForum()) { } else if (history && history->peer->isForum()) {
controller->openForum(history->peer->asChannel()); controller->openForum(history->peer->asChannel());
} else if (history) { } else if (history) {

View file

@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum_topic.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
namespace Dialogs::Ui { namespace Dialogs::Ui {
@ -852,6 +853,7 @@ void RowPainter::paint(
bool paused) { bool paused) {
const auto entry = row->entry(); const auto entry = row->entry();
const auto history = row->history(); const auto history = row->history();
const auto topic = row->topic();
const auto peer = history ? history->peer.get() : nullptr; const auto peer = history ? history->peer.get() : nullptr;
const auto unreadCount = entry->chatListUnreadCount(); const auto unreadCount = entry->chatListUnreadCount();
const auto unreadMark = entry->chatListUnreadMark(); const auto unreadMark = entry->chatListUnreadMark();
@ -960,22 +962,23 @@ void RowPainter::paint(
color, color,
ms) ms)
: false; : false;
const auto view = actionWasPainted
? nullptr
: history
? &history->lastItemDialogsView
: topic
? &topic->lastItemDialogsView
: nullptr;
if (const auto folder = row->folder()) { if (const auto folder = row->folder()) {
PaintListEntryText(p, rect, active, selected, row, ms, paused); PaintListEntryText(p, rect, active, selected, row, ms, paused);
} else if (history && !actionWasPainted) { } else if (view) {
if (!history->lastItemDialogsView.prepared(item)) { if (!view->prepared(item)) {
history->lastItemDialogsView.prepare( view->prepare(
item, item,
[=] { history->updateChatListEntry(); }, [=] { entry->updateChatListEntry(); },
{}); {});
} }
history->lastItemDialogsView.paint( view->paint(p, rect, active, selected, ms, paused);
p,
rect,
active,
selected,
ms,
paused);
} }
}; };
const auto paintCounterCallback = [&] { const auto paintCounterCallback = [&] {

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_send_action.h" #include "data/data_send_action.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_chat.h" #include "data/data_chat.h"
@ -159,6 +160,15 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
if (IsClientMsgId(item->id)) { if (IsClientMsgId(item->id)) {
unregisterClientSideMessage(item); unregisterClientSideMessage(item);
} }
if (const auto forum = peer->forum()) {
if (const auto topic = forum->topicFor(item)) {
if (topic->rootId() == item->id) {
forum->applyTopicRemoved(item->id);
} else {
topic->applyItemRemoved(item->id);
}
}
}
if (const auto chat = peer->asChat()) { if (const auto chat = peer->asChat()) {
if (const auto to = chat->getMigrateToChannel()) { if (const auto to = chat->getMigrateToChannel()) {
if (const auto history = owner().historyLoaded(to)) { if (const auto history = owner().historyLoaded(to)) {
@ -1124,9 +1134,13 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
if (!folderKnown()) { if (!folderKnown()) {
owner().histories().requestDialogEntry(this); owner().histories().requestDialogEntry(this);
} }
if (item->isTopicStart() && peer->isForum()) { if (peer->isForum()) {
if (const auto forum = peer->asChannel()->forum()) { if (const auto forum = peer->asChannel()->forum()) {
forum->topicAdded(item); /*if (item->isTopicStart()) { // #TODO forum isTopicStart legacy?
forum->topicAdded(item);
} else */if (const auto topic = forum->topicFor(item)) {
topic->applyItemAdded(item);
}
} }
} }
} }

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/history_view_item_preview.h" #include "history/view/history_view_item_preview.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "data/data_game.h" #include "data/data_game.h"
@ -771,6 +772,10 @@ void HistoryService::applyAction(const MTPMessageAction &action) {
this, this,
_from, _from,
data.vmonths().v); data.vmonths().v);
}, [&](const MTPDmessageActionTopicCreate &data) {
if (const auto forum = history()->peer->forum()) {
forum->applyTopicAdded(id, qs(data.vtitle()));
}
}, [](const auto &) { }, [](const auto &) {
}); });
} }