From b4d1ba07a652173e25999b04ced97e87b4cbba2e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 5 Sep 2025 14:23:06 +0400 Subject: [PATCH] Initial forum support in bots data classes. --- .../SourceFiles/api/api_messages_search.cpp | 19 +++--- Telegram/SourceFiles/apiwrap.cpp | 11 ++- .../boxes/peer_list_controllers.cpp | 2 +- .../boxes/peers/edit_forum_topic_box.cpp | 2 +- Telegram/SourceFiles/core/application.cpp | 2 +- Telegram/SourceFiles/data/data_channel.cpp | 6 -- Telegram/SourceFiles/data/data_channel.h | 2 - Telegram/SourceFiles/data/data_forum.cpp | 40 ++++++++--- Telegram/SourceFiles/data/data_forum.h | 4 +- .../SourceFiles/data/data_forum_topic.cpp | 30 ++++++--- Telegram/SourceFiles/data/data_forum_topic.h | 4 +- Telegram/SourceFiles/data/data_histories.cpp | 1 + Telegram/SourceFiles/data/data_peer.cpp | 38 +++++++++-- Telegram/SourceFiles/data/data_peer.h | 4 ++ .../SourceFiles/data/data_peer_values.cpp | 49 +++++++------- .../SourceFiles/data/data_replies_list.cpp | 4 +- .../SourceFiles/data/data_saved_sublist.cpp | 4 +- .../data/data_search_controller.cpp | 8 ++- Telegram/SourceFiles/data/data_session.cpp | 42 ++++++++---- Telegram/SourceFiles/data/data_user.cpp | 47 ++++++++++++- Telegram/SourceFiles/data/data_user.h | 17 +++++ Telegram/SourceFiles/data/data_web_page.cpp | 21 ++++-- .../data/notify/data_notify_settings.cpp | 4 +- .../dialogs/dialogs_inner_widget.cpp | 32 +++++---- .../SourceFiles/dialogs/dialogs_widget.cpp | 67 ++++++++++--------- .../history/history_unread_things.cpp | 4 +- .../SourceFiles/history/history_widget.cpp | 8 ++- .../view/history_view_chat_preview.cpp | 2 +- .../view/history_view_contact_status.cpp | 4 +- .../history/view/history_view_element.cpp | 6 +- .../history/view/history_view_message.cpp | 2 +- .../view/history_view_top_bar_widget.cpp | 2 +- Telegram/SourceFiles/info/info_controller.cpp | 2 +- .../info/media/info_media_widget.cpp | 2 +- .../info/profile/info_profile_actions.cpp | 6 +- .../info/profile/info_profile_cover.cpp | 2 +- .../info/profile/info_profile_values.cpp | 4 +- .../info/profile/info_profile_widget.cpp | 2 +- .../SourceFiles/window/window_peer_menu.cpp | 23 ++++--- .../window/window_session_controller.cpp | 22 +++--- 40 files changed, 369 insertions(+), 182 deletions(-) diff --git a/Telegram/SourceFiles/api/api_messages_search.cpp b/Telegram/SourceFiles/api/api_messages_search.cpp index fb390564ef..bc92501eb4 100644 --- a/Telegram/SourceFiles/api/api_messages_search.cpp +++ b/Telegram/SourceFiles/api/api_messages_search.cpp @@ -159,6 +159,7 @@ void MessagesSearch::searchReceived( // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); + _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); const auto total = int(data.vmessages().v.size()); @@ -168,6 +169,7 @@ void MessagesSearch::searchReceived( // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); + _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); // data.vnext_rate() is used only in global search. @@ -178,17 +180,14 @@ void MessagesSearch::searchReceived( // Don't apply cached data! owner.processUsers(data.vusers()); owner.processChats(data.vchats()); - } - if (const auto channel = _history->peer->asChannel()) { - channel->ptsReceived(data.vpts().v); - if (_requestId != 0) { - // Don't apply cached data! - channel->processTopics(data.vtopics()); + if (const auto channel = _history->peer->asChannel()) { + channel->ptsReceived(data.vpts().v); + } else { + LOG(("API Error: " + "received messages.channelMessages when no channel " + "was passed!")); } - } else { - LOG(("API Error: " - "received messages.channelMessages when no channel " - "was passed!")); + _history->peer->processTopics(data.vtopics()); } auto items = HistoryItemsFromTL(&owner, data.vmessages().v); const auto total = int(data.vcount().v); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 64de5717fa..1520f5cd98 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -362,6 +362,9 @@ void ApiWrap::savePinnedOrder(Data::Folder *folder) { } void ApiWrap::savePinnedOrder(not_null forum) { + if (!forum->channel()) { + return; + } const auto &order = _session->data().pinnedChatsOrder(forum); const auto input = [](Dialogs::Key key) { if (const auto topic = key.topic()) { @@ -1889,7 +1892,7 @@ void ApiWrap::sendNotifySettingsUpdates() { for (const auto topic : base::take(_updateNotifyTopics)) { request(MTPaccount_UpdateNotifySettings( MTP_inputNotifyForumTopic( - topic->channel()->input, + topic->peer()->input, MTP_int(topic->rootId())), topic->notify().serialize() )).afterDelay(kSmallDelayMs).send(); @@ -3054,18 +3057,20 @@ void ApiWrap::requestMessageAfterDate( return &messages.vmessages().v; }; const auto list = result.match([&]( - const MTPDmessages_messages &data) { + const MTPDmessages_messages &data) { + peer->processTopics(data.vtopics()); return handleMessages(data); }, [&](const MTPDmessages_messagesSlice &data) { + peer->processTopics(data.vtopics()); return handleMessages(data); }, [&](const MTPDmessages_channelMessages &data) { if (const auto channel = peer->asChannel()) { channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (ApiWrap::jumpToDate)")); } + peer->processTopics(data.vtopics()); return handleMessages(data); }, [&](const MTPDmessages_messagesNotModified &) { LOG(("API Error: received messages.messagesNotModified! " diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index b962012f51..3b984c171a 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -983,7 +983,7 @@ void ChooseTopicSearchController::searchQuery(const QString &query) { void ChooseTopicSearchController::searchOnServer() { _requestId = _api.request(MTPmessages_GetForumTopics( MTP_flags(MTPmessages_GetForumTopics::Flag::f_q), - _forum->channel()->input, + _forum->peer()->input, MTP_string(_query), MTP_int(_offsetDate), MTP_int(_offsetId), diff --git a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp index 354a5608f5..a3bff741f1 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_forum_topic_box.cpp @@ -560,7 +560,7 @@ void EditForumTopicBox( state->requestId = api->request(MTPmessages_EditForumTopic( MTP_flags(Flag::f_title | (topic->isGeneral() ? Flag() : Flag::f_icon_emoji_id)), - topic->channel()->input, + topic->peer()->input, MTP_int(rootId), MTP_string(title->getLastText().trimmed()), MTP_long(state->iconId.current()), diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 933e248d05..e24cb260ea 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -1392,7 +1392,7 @@ Window::Controller *Application::windowForShowingHistory( Window::Controller *Application::windowForShowingForum( not_null forum) const { - const auto tabs = forum->channel()->useSubsectionTabs(); + const auto tabs = forum->bot() || forum->peer()->useSubsectionTabs(); const auto id = Window::SeparateId( tabs ? Window::SeparateType::Chat : Window::SeparateType::Forum, forum->history()); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 08321386f9..4f3a59d691 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -1182,12 +1182,6 @@ void ChannelData::setStoriesState(StoriesState state) { } } -void ChannelData::processTopics(const MTPVector &topics) { - if (const auto forum = this->forum()) { - forum->applyReceivedTopics(topics); - } -} - int ChannelData::levelHint() const { return _levelHint; } diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 4bf99d75f3..e9290a5cbe 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -545,8 +545,6 @@ public: return mgInfo ? mgInfo->monoforum() : nullptr; } - void processTopics(const MTPVector &topics); - [[nodiscard]] int levelHint() const; void updateLevelHint(int levelHint); diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index e125fe21e3..b03ae2fae9 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_forum_icons.h" #include "data/data_forum_topic.h" #include "data/data_replies_list.h" +#include "data/data_user.h" #include "data/notify/data_notify_settings.h" #include "history/history.h" #include "history/history_item.h" @@ -48,12 +49,13 @@ constexpr auto kShowTopicNamesCount = 8; Forum::Forum(not_null history) : _history(history) , _topicsList(&session(), {}, owner().maxPinnedChatsLimitValue(this)) { - Expects(_history->peer->isChannel()); + Expects(_history->peer->isChannel() + || _history->peer->isBot()); if (_history->inChatList()) { preloadTopics(); } - if (channel()->canCreateTopics()) { + if (peer()->canCreateTopics()) { owner().forumIcons().requestDefaultIfUnknown(); } } @@ -98,7 +100,15 @@ not_null Forum::history() const { return _history; } -not_null Forum::channel() const { +not_null Forum::peer() const { + return _history->peer; +} + +UserData *Forum::bot() const { + return _history->peer->asBot(); +} + +ChannelData *Forum::channel() const { return _history->peer->asChannel(); } @@ -107,6 +117,14 @@ not_null Forum::topicsList() { } rpl::producer<> Forum::destroyed() const { + if (const auto bot = this->bot()) { + return bot->flagsValue( + ) | rpl::filter([=](const UserData::Flags::Change &update) { + using Flag = UserData::Flag; + return (update.diff & Flag::Forum) + && !(update.value & Flag::Forum); + }) | rpl::take(1) | rpl::to_empty; + } return channel()->flagsValue( ) | rpl::filter([=](const ChannelData::Flags::Change &update) { using Flag = ChannelData::Flag; @@ -144,7 +162,7 @@ void Forum::requestTopics() { const auto loadCount = firstLoad ? kTopicsFirstLoad : kTopicsPerPage; _requestId = session().api().request(MTPmessages_GetForumTopics( MTP_flags(0), - channel()->input, + peer()->input, MTPstring(), // q MTP_int(_offset.date), MTP_int(_offset.id), @@ -169,7 +187,7 @@ void Forum::requestTopics() { }).fail([=](const MTP::Error &error) { _requestId = 0; _topicsList.setLoaded(); - if (error.type() == u"CHANNEL_FORUM_MISSING"_q) { + if (error.type() == u"CHANNEL_FORUM_MISSING"_q && channel()) { const auto flags = channel()->flags() & ~ChannelDataFlag::Forum; channel()->setFlags(flags); } @@ -280,7 +298,7 @@ Thread *Forum::activeSubsectionThread() const { } void Forum::markUnreadCountsUnknown(MsgId readTillId) { - if (!channel()->useSubsectionTabs()) { + if (!peer()->useSubsectionTabs()) { return; } for (const auto &[rootId, topic] : _topics) { @@ -294,7 +312,7 @@ void Forum::markUnreadCountsUnknown(MsgId readTillId) { void Forum::updateUnreadCounts( MsgId readTillId, const base::flat_map, int> &counts) { - if (!channel()->useSubsectionTabs()) { + if (!peer()->useSubsectionTabs()) { return; } for (const auto &[rootId, topic] : _topics) { @@ -331,7 +349,9 @@ void Forum::applyReceivedTopics( owner().processUsers(data.vusers()); owner().processChats(data.vchats()); owner().processMessages(data.vmessages(), NewMessageType::Existing); - channel()->ptsReceived(data.vpts().v); + if (const auto channel = this->channel()) { + channel->ptsReceived(data.vpts().v); + } applyReceivedTopics(data.vtopics(), std::move(callback)); if (!_staleRootIds.empty()) { requestSomeStale(); @@ -405,7 +425,7 @@ void Forum::requestSomeStale() { Fn finish) { return session().api().request( MTPmessages_GetForumTopicsByID( - channel()->input, + peer()->input, MTP_vector(rootIds)) ).done([=](const MTPmessages_ForumTopics &result) { _staleRequestId = 0; @@ -439,7 +459,7 @@ void Forum::requestTopic(MsgId rootId, Fn done) { if (!request.id && _staleRootIds.emplace(rootId).second && (_staleRootIds.size() == 1)) { - crl::on_main(&session(), [peer = channel()] { + crl::on_main(&session(), [peer = peer()] { if (const auto forum = peer->forum()) { forum->requestSomeStale(); } diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index cccacadeef..0b38ca6232 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -41,8 +41,10 @@ public: [[nodiscard]] Session &owner() const; [[nodiscard]] Main::Session &session() const; + [[nodiscard]] not_null peer() const; [[nodiscard]] not_null history() const; - [[nodiscard]] not_null channel() const; + [[nodiscard]] UserData *bot() const; + [[nodiscard]] ChannelData *channel() const; [[nodiscard]] not_null topicsList(); [[nodiscard]] rpl::producer<> destroyed() const; [[nodiscard]] auto topicDestroyed() const diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 721fb2bc41..35a3a662c9 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -265,7 +265,15 @@ std::shared_ptr ForumTopic::replies() const { return _replies; } -not_null ForumTopic::channel() const { +not_null ForumTopic::peer() const { + return _forum->peer(); +} + +UserData *ForumTopic::bot() const { + return _forum->bot(); +} + +ChannelData *ForumTopic::channel() const { return _forum->channel(); } @@ -308,14 +316,18 @@ bool ForumTopic::my() const { } bool ForumTopic::canEdit() const { - return my() || channel()->canManageTopics(); + return my() || peer()->canManageTopics(); } bool ForumTopic::canDelete() const { if (creating() || isGeneral()) { return false; - } else if (channel()->canDeleteMessages()) { + } else if (bot()) { return true; + } else if (const auto channel = this->channel()) { + if (channel->canDeleteMessages()) { + return true; + } } return my() && replies()->canDeleteMyTopic(); } @@ -325,7 +337,7 @@ bool ForumTopic::canToggleClosed() const { } bool ForumTopic::canTogglePinned() const { - return !creating() && channel()->canManageTopics(); + return !creating() && peer()->canManageTopics(); } bool ForumTopic::creating() const { @@ -405,7 +417,7 @@ void ForumTopic::applyTopic(const MTPDforumTopic &data) { draft->match([&](const MTPDdraftMessage &data) { Data::ApplyPeerCloudDraft( &session(), - channel()->id, + peer()->id, _rootId, PeerId(), data); @@ -465,12 +477,12 @@ void ForumTopic::setClosedAndSave(bool closed) { const auto weak = base::make_weak(this); api->request(MTPmessages_EditForumTopic( MTP_flags(MTPmessages_EditForumTopic::Flag::f_closed), - channel()->input, + peer()->input, MTP_int(_rootId), MTPstring(), // title MTPlong(), // icon_emoji_id MTP_bool(closed), - MTPBool() // hidden + MTPBool() // hiddenKO )).done([=](const MTPUpdates &result) { api->applyUpdates(result); }).fail([=](const MTP::Error &error) { @@ -527,7 +539,7 @@ int ForumTopic::chatListNameVersion() const { void ForumTopic::applyTopicTopMessage(MsgId topMessageId) { if (topMessageId) { growLastKnownServerMessageId(topMessageId); - const auto itemId = FullMsgId(channel()->id, topMessageId); + const auto itemId = FullMsgId(peer()->id, topMessageId); if (const auto item = owner().message(itemId)) { setLastServerMessage(item); resolveChatListMessageGroup(); @@ -895,7 +907,7 @@ Dialogs::BadgesState ForumTopic::chatListBadgesState() const { Dialogs::CountInBadge::Messages, Dialogs::IncludeInBadge::All); if (!result.unread && _replies->inboxReadTillId() < 2) { - result.unread = channel()->amIn() + result.unread = (bot() || (channel() && channel()->amIn())) && (_lastKnownServerMessageId > history()->inboxReadTillId()); result.unreadMuted = muted(); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 6b8d81ff0a..49e299f963 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -91,7 +91,9 @@ public: } [[nodiscard]] std::shared_ptr replies() const; - [[nodiscard]] not_null channel() const; + [[nodiscard]] not_null peer() const; + [[nodiscard]] UserData *bot() const; + [[nodiscard]] ChannelData *channel() const; [[nodiscard]] not_null history() const; [[nodiscard]] not_null forum() const; [[nodiscard]] rpl::producer<> destroyed() const; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 408e9e85db..bc5587c631 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -548,6 +548,7 @@ void Histories::requestFakeChatListMessage( _fakeChatListRequests.erase(history); history->setFakeChatListMessageFrom(MTP_messages_messages( MTP_vector(0), + MTP_vector(0), MTP_vector(0), MTP_vector(0))); finish(); diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 9509f171f0..e062bfcc0e 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -693,7 +693,9 @@ bool PeerData::canCreateTodoLists() const { } bool PeerData::canCreateTopics() const { - if (const auto channel = asChannel()) { + if (const auto bot = asBot()) { + return bot->isForum(); + } else if (const auto channel = asChannel()) { return channel->isForum() && !channel->amRestricted(ChatRestriction::CreateTopics); } @@ -701,7 +703,9 @@ bool PeerData::canCreateTopics() const { } bool PeerData::canManageTopics() const { - if (const auto channel = asChannel()) { + if (const auto bot = asBot()) { + return bot->isForum(); + } else if (const auto channel = asChannel()) { return channel->isForum() && (channel->amCreator() || (channel->adminRights() & ChatAdminRight::ManageTopics)); @@ -1436,7 +1440,9 @@ bool PeerData::isBroadcast() const { } bool PeerData::isForum() const { - if (const auto channel = asChannel()) { + if (const auto bot = asBot()) { + return bot->isForum(); + } else if (const auto channel = asChannel()) { return channel->isForum(); } return false; @@ -1517,7 +1523,9 @@ Ui::BotVerifyDetails *PeerData::botVerifyDetails() const { } Data::Forum *PeerData::forum() const { - if (const auto channel = asChannel()) { + if (const auto bot = asBot()) { + return bot->forum(); + } else if (const auto channel = asChannel()) { return channel->forum(); } return nullptr; @@ -1549,6 +1557,28 @@ Data::SavedSublist *PeerData::monoforumSublistFor( return nullptr; } +bool PeerData::useSubsectionTabs() const { + if (const auto bot = asBot()) { + return bot->isForum(); + } else if (const auto channel = asChannel()) { + return channel->useSubsectionTabs(); + } + return false; +} + +bool PeerData::viewForumAsMessages() const { + if (const auto channel = asChannel()) { + return channel->viewForumAsMessages(); + } + return false; +} + +void PeerData::processTopics(const MTPVector &topics) { + if (const auto forum = this->forum()) { + forum->applyReceivedTopics(topics); + } +} + bool PeerData::allowsForwarding() const { if (isUser()) { return true; diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index f51fb55f3b..378d6374aa 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -271,6 +271,10 @@ public: [[nodiscard]] Data::SavedSublist *monoforumSublistFor( PeerId sublistPeerId) const; + [[nodiscard]] bool useSubsectionTabs() const; + [[nodiscard]] bool viewForumAsMessages() const; + void processTopics(const MTPVector &topics); + [[nodiscard]] Data::PeerNotifySettings ¬ify() { return _notify; } diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index 77fdb049b3..1e09e5978c 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -182,30 +182,31 @@ inline auto DefaultRestrictionValue( | Flag::HasLink | Flag::Forbidden | Flag::Creator; - const auto channel = topic->channel(); - return rpl::combine( - PeerFlagsValue(channel.get(), mask), - RestrictionsValue(channel, rights), - DefaultRestrictionsValue(channel, rights), - AdminRightsValue(channel, ChatAdminRight::ManageTopics), - topic->session().changes().topicFlagsValue( - topic, - TopicUpdate::Flag::Closed), - [=]( - ChannelDataFlags flags, - ChatRestrictions sendRestriction, - ChatRestrictions defaultSendRestriction, - auto, - auto) { - const auto notAmInFlags = Flag::Left | Flag::Forbidden; - const auto allowed = !(flags & notAmInFlags) - || ((flags & Flag::HasLink) - && !(flags & Flag::JoinToWrite)); - return allowed - && ((flags & Flag::Creator) - || (!sendRestriction && !defaultSendRestriction)) - && (!topic->closed() || topic->canToggleClosed()); - }); + if (const auto channel = topic->channel()) { + return rpl::combine( + PeerFlagsValue(channel, mask), + RestrictionsValue(channel, rights), + DefaultRestrictionsValue(channel, rights), + AdminRightsValue(channel, ChatAdminRight::ManageTopics), + topic->session().changes().topicFlagsValue( + topic, + TopicUpdate::Flag::Closed), + [=]( + ChannelDataFlags flags, + ChatRestrictions sendRestriction, + ChatRestrictions defaultSendRestriction, + auto, + auto) { + const auto notAmInFlags = Flag::Left | Flag::Forbidden; + const auto allowed = !(flags & notAmInFlags) + || ((flags & Flag::HasLink) + && !(flags & Flag::JoinToWrite)); + return allowed + && ((flags & Flag::Creator) + || (!sendRestriction && !defaultSendRestriction)) + && (!topic->closed() || topic->canToggleClosed()); + }); + } } return CanSendAnyOfValue(thread->peer(), rights, forbidInForums); } diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp index f334c47d1d..c34b10f672 100644 --- a/Telegram/SourceFiles/data/data_replies_list.cpp +++ b/Telegram/SourceFiles/data/data_replies_list.cpp @@ -691,17 +691,19 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { "(HistoryWidget::messagesReceived)")); return 0; }, [&](const MTPDmessages_messages &data) { + _history->peer->processTopics(data.vtopics()); return int(data.vmessages().v.size()); }, [&](const MTPDmessages_messagesSlice &data) { + _history->peer->processTopics(data.vtopics()); return data.vcount().v; }, [&](const MTPDmessages_channelMessages &data) { if (const auto channel = _history->peer->asChannel()) { channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (HistoryWidget::messagesReceived)")); } + _history->peer->processTopics(data.vtopics()); return data.vcount().v; }); diff --git a/Telegram/SourceFiles/data/data_saved_sublist.cpp b/Telegram/SourceFiles/data/data_saved_sublist.cpp index 58435044e4..69473cdc83 100644 --- a/Telegram/SourceFiles/data/data_saved_sublist.cpp +++ b/Telegram/SourceFiles/data/data_saved_sublist.cpp @@ -372,17 +372,19 @@ bool SavedSublist::processMessagesIsEmpty( "(HistoryWidget::messagesReceived)")); return 0; }, [&](const MTPDmessages_messages &data) { + owningHistory()->peer->processTopics(data.vtopics()); return int(data.vmessages().v.size()); }, [&](const MTPDmessages_messagesSlice &data) { + owningHistory()->peer->processTopics(data.vtopics()); return data.vcount().v; }, [&](const MTPDmessages_channelMessages &data) { if (const auto channel = owningHistory()->peer->asChannel()) { channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (HistoryWidget::messagesReceived)")); } + owningHistory()->peer->processTopics(data.vtopics()); return data.vcount().v; }); diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 6b43192805..4d599c135b 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -205,6 +205,7 @@ SearchResult ParseSearchResult( auto &d = data.c_messages_messages(); peer->owner().processUsers(d.vusers()); peer->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); result.fullCount = d.vmessages().v.size(); return &d.vmessages().v; } break; @@ -213,21 +214,22 @@ SearchResult ParseSearchResult( auto &d = data.c_messages_messagesSlice(); peer->owner().processUsers(d.vusers()); peer->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); result.fullCount = d.vcount().v; return &d.vmessages().v; } break; case mtpc_messages_channelMessages: { const auto &d = data.c_messages_channelMessages(); + peer->owner().processUsers(d.vusers()); + peer->owner().processChats(d.vchats()); if (const auto channel = peer->asChannel()) { channel->ptsReceived(d.vpts().v); - channel->processTopics(d.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (ParseSearchResult)")); } - peer->owner().processUsers(d.vusers()); - peer->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); result.fullCount = d.vcount().v; return &d.vmessages().v; } break; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index c14a6ceece..06d00cbcd2 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -397,15 +397,24 @@ void Session::clear() { // We must clear all [mono]forums before clearing customEmojiManager. // Because in Data::ForumTopic an Ui::Text::CustomEmoji is cached. - auto forums = base::flat_set>(); + auto botForums = base::flat_set>(); + auto channelForums = base::flat_set>(); for (const auto &[peerId, peer] : _peers) { + if (const auto bot = peer->asBot()) { + if (bot->isForum()) { + botForums.emplace(bot); + } + } if (const auto channel = peer->asChannel()) { if (channel->isForum() || channel->amMonoforumAdmin()) { - forums.emplace(channel); + channelForums.emplace(channel); } } } - for (const auto &channel : forums) { + for (const auto &bot : botForums) { + bot->setFlags(bot->flags() & ~UserDataFlag::Forum); + } + for (const auto &channel : channelForums) { channel->setFlags(channel->flags() & ~(ChannelDataFlag::Forum | ChannelDataFlag::MonoforumAdmin)); } @@ -564,6 +573,7 @@ not_null Session::processUser(const MTPUser &data) { | Flag::Scam | Flag::Fake | Flag::BotInlineGeo + | Flag::Forum | Flag::Premium | Flag::Support | Flag::HasRequirePremiumToWrite @@ -590,6 +600,7 @@ not_null Session::processUser(const MTPUser &data) { | (data.is_scam() ? Flag::Scam : Flag()) | (data.is_fake() ? Flag::Fake : Flag()) | (data.is_bot_inline_geo() ? Flag::BotInlineGeo : Flag()) + | (data.is_bot_forum_view() ? Flag::Forum : Flag()) | (data.is_premium() ? Flag::Premium : Flag()) | (data.is_support() ? Flag::Support : Flag()) | (hasRequirePremiumToWrite @@ -2681,15 +2692,6 @@ void Session::processMessages( void Session::processExistingMessages( ChannelData *channel, const MTPmessages_Messages &data) { - data.match([&](const MTPDmessages_channelMessages &data) { - if (channel) { - channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); - } else { - LOG(("App Error: received messages.channelMessages!")); - } - }, [](const auto &) {}); - data.match([&](const MTPDmessages_messagesNotModified&) { LOG(("API Error: received messages.messagesNotModified!")); }, [&](const auto &data) { @@ -2697,6 +2699,19 @@ void Session::processExistingMessages( processChats(data.vchats()); processMessages(data.vmessages(), NewMessageType::Existing); }); + data.match([&](const MTPDmessages_channelMessages &data) { + if (channel) { + channel->ptsReceived(data.vpts().v); + } else { + LOG(("App Error: received messages.channelMessages!")); + } + }, [](const auto &) {}); + data.match([&](const MTPDmessages_messagesNotModified&) { + }, [&](const auto &data) { + if (channel) { + channel->processTopics(data.vtopics()); + } + }); } const Session::Messages *Session::messagesList(PeerId peerId) const { @@ -5174,6 +5189,9 @@ void Session::saveViewAsMessages( not_null forum, bool viewAsMessages) { const auto channel = forum->channel(); + if (!channel) { + return; + } if (const auto requestId = _viewAsMessagesRequests.take(channel)) { _session->api().request(*requestId).cancel(); } diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 638aa1ff7c..f0cac38de6 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/business/data_business_info.h" #include "data/components/credits.h" #include "data/data_cloud_themes.h" +#include "data/data_forum.h" +#include "data/data_forum_icons.h" #include "data/data_saved_music.h" #include "data/data_session.h" #include "data/data_changes.h" @@ -84,6 +86,28 @@ bool ApplyBotVerifierSettings( BotInfo::BotInfo() = default; +BotInfo::~BotInfo() = default; + +void BotInfo::ensureForum(not_null that) { + if (!_forum) { + const auto history = that->owner().history(that); + _forum = std::make_unique(history); + history->forumChanged(nullptr); + } +} + +Data::Forum *BotInfo::forum() const { + return _forum.get(); +} + +std::unique_ptr BotInfo::takeForumData() { + if (auto result = base::take(_forum)) { + result->history()->forumChanged(result.get()); + return result; + } + return nullptr; +} + Data::LastseenStatus LastseenFromMTP( const MTPUserStatus &status, Data::LastseenStatus currentStatus) { @@ -471,12 +495,31 @@ void UserData::setAccessHash(uint64 accessHash) { } void UserData::setFlags(UserDataFlags which) { - if ((which & UserDataFlag::Deleted) - != (flags() & UserDataFlag::Deleted)) { + if (!isBot()) { + which &= ~UserDataFlag::Forum; + } + const auto diff = flags() ^ which; + if (diff & UserDataFlag::Deleted) { invalidateEmptyUserpic(); } + // Let Data::Forum live till the end of _flags.set. + // That way the data can be used in changes handler. + // Example: render frame for forum auto-closing animation. + const auto takenForum = (botInfo + && (diff & Flag::Forum) + && !(which & Flag::Forum)) + ? botInfo->takeForumData() + : nullptr; + if ((diff & Flag::Forum) && (which & Flag::Forum)) { + if (const auto info = botInfo.get()) { + info->ensureForum(this); + } + } _flags.set((flags() & UserDataFlag::Self) | (which & ~UserDataFlag::Self)); + if (const auto raw = takenForum.get()) { + owner().forumIcons().clearUserpicsReset(raw); + } } void UserData::addFlags(UserDataFlags which) { diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 435692cda6..f86ddbe485 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/flags.h" namespace Data { +class Forum; struct BotCommand; struct BusinessDetails; } // namespace Data @@ -55,6 +56,11 @@ struct BotVerifierSettings { struct BotInfo { BotInfo(); + ~BotInfo(); + + void ensureForum(not_null that); + [[nodiscard]] Data::Forum *forum() const; + [[nodiscard]] std::unique_ptr takeForumData(); QString description; QString inlinePlaceholder; @@ -92,6 +98,10 @@ struct BotInfo { bool canManageEmojiStatus : 1 = false; bool supportsBusiness : 1 = false; bool hasMainApp : 1 = false; + +private: + std::unique_ptr _forum; + }; enum class UserDataFlag : uint32 { @@ -122,6 +132,7 @@ enum class UserDataFlag : uint32 { MessageMoneyRestrictionsKnown = (1 << 24), ReadDatesPrivate = (1 << 25), StoriesCorrespondent = (1 << 26), + Forum = (1ULL << 27), }; inline constexpr bool is_flag_type(UserDataFlag) { return true; }; using UserDataFlags = base::flags; @@ -188,6 +199,12 @@ public: [[nodiscard]] bool messageMoneyRestrictionsKnown() const; [[nodiscard]] bool canSendIgnoreMoneyRestrictions() const; [[nodiscard]] bool readDatesPrivate() const; + [[nodiscard]] bool isForum() const { + return flags() & Flag::Forum; + } + [[nodiscard]] Data::Forum *forum() const { + return botInfo ? botInfo->forum() : nullptr; + } void setStoriesCorrespondent(bool is); [[nodiscard]] bool storiesCorrespondent() const; diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index 9c63bb1118..bf9728dac9 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -340,6 +340,16 @@ void WebPageData::ApplyChanges( not_null session, ChannelData *channel, const MTPmessages_Messages &result) { + const auto list = result.match([]( + const MTPDmessages_messagesNotModified &) { + LOG(("API Error: received messages.messagesNotModified! " + "(WebPageData::ApplyChanges)")); + return static_cast*>(nullptr); + }, [&](const auto &data) { + session->data().processUsers(data.vusers()); + session->data().processChats(data.vchats()); + return &data.vmessages().v; + }); result.match([&]( const MTPDmessages_channelMessages &data) { if (channel) { @@ -351,15 +361,12 @@ void WebPageData::ApplyChanges( } }, [&](const auto &) { }); - const auto list = result.match([]( + result.match([]( const MTPDmessages_messagesNotModified &) { - LOG(("API Error: received messages.messagesNotModified! " - "(WebPageData::ApplyChanges)")); - return static_cast*>(nullptr); }, [&](const auto &data) { - session->data().processUsers(data.vusers()); - session->data().processChats(data.vchats()); - return &data.vmessages().v; + if (channel) { + channel->processTopics(data.vtopics()); + } }); if (!list) { return; diff --git a/Telegram/SourceFiles/data/notify/data_notify_settings.cpp b/Telegram/SourceFiles/data/notify/data_notify_settings.cpp index beb47698b7..299b7fc61b 100644 --- a/Telegram/SourceFiles/data/notify/data_notify_settings.cpp +++ b/Telegram/SourceFiles/data/notify/data_notify_settings.cpp @@ -96,7 +96,7 @@ void NotifySettings::request(not_null thread) { if (topic->notify().settingsUnknown()) { topic->session().api().requestNotifySettings( MTP_inputNotifyForumTopic( - topic->channel()->input, + topic->peer()->input, MTP_int(topic->rootId()))); } } @@ -507,7 +507,7 @@ bool NotifySettings::soundUnknown(not_null thread) const { const auto topic = thread->asTopic(); return (topic && topic->notify().settingsUnknown()) || ((!topic || !topic->notify().sound().has_value()) - && soundUnknown(topic->channel())); + && soundUnknown(topic->peer())); } bool NotifySettings::isMuted( diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 893eacc6fb..3d31a221d6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1478,7 +1478,7 @@ bool InnerWidget::isRowActive( return true; } else if (const auto topic = entry.key.topic()) { if (const auto history = key.history()) { - return (history->peer == topic->channel()) + return (history->peer == topic->peer()) && HistoryView::SubsectionTabs::UsedFor(history); } return false; @@ -3611,18 +3611,24 @@ void InnerWidget::trackResultsHistory(not_null history) { if (!_trackedHistories.emplace(history).second) { return; } - const auto channel = history->peer->asChannel(); - if (!channel || channel->isBroadcast()) { + const auto peer = history->peer; + if (!peer->isBot() && !peer->isMegagroup()) { return; } - channel->flagsValue( - ) | rpl::skip( - 1 - ) | rpl::filter([=](const ChannelData::Flags::Change &change) { - return (change.diff & ChannelDataFlag::Forum); - }) | rpl::start_with_next([=] { + auto changes = peer->isBot() + ? peer->asBot()->flagsValue() | rpl::skip( + 1 + ) | rpl::filter([=](const UserData::Flags::Change &change) { + return change.diff & UserDataFlag::Forum; + }) | rpl::to_empty | rpl::type_erased() + : peer->asChannel()->flagsValue() | rpl::skip( + 1 + ) | rpl::filter([=](const ChannelData::Flags::Change &change) { + return (change.diff & ChannelDataFlag::Forum); + }) | rpl::to_empty | rpl::type_erased(); + std::move(changes) | rpl::start_with_next([=] { for (const auto &row : _searchResults) { - if (row->item()->history()->peer == channel) { + if (row->item()->history()->peer == peer) { row->invalidateTopic(); } } @@ -3630,7 +3636,7 @@ void InnerWidget::trackResultsHistory(not_null history) { for (auto i = begin(_filterResultsGlobal) ; i != end(_filterResultsGlobal);) { if (const auto topic = i->first.topic()) { - if (topic->channel() == channel) { + if (topic->peer() == peer) { removed = true; _filterResults.erase( ranges::remove( @@ -3651,7 +3657,7 @@ void InnerWidget::trackResultsHistory(not_null history) { update(); }, _trackedLifetime); - if (const auto forum = channel->forum()) { + if (const auto forum = peer->forum()) { forum->topicDestroyed( ) | rpl::start_with_next([=](not_null topic) { auto removed = false; @@ -4284,7 +4290,7 @@ void InnerWidget::updateSearchIn() { const auto peer = _searchState.inChat.owningHistory() ? _searchState.inChat.owningHistory()->peer.get() : _openedForum - ? _openedForum->channel().get() + ? _openedForum->peer().get() : nullptr; const auto paused = [window = _controller] { return window->isGifPausedAtLeastFor(Window::GifPauseReason::Any); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 1dedffae5f..016996e655 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -875,7 +875,7 @@ void Widget::chosenRow(const ChosenRow &row) { controller()->showInNewWindow(Window::SeparateId(topicJump)); } else { if (!controller()->adaptive().isOneColumn() - && !topicJump->channel()->useSubsectionTabs()) { + && !topicJump->peer()->useSubsectionTabs()) { controller()->showForum( topicJump->forum(), Window::SectionShow().withChildColumn()); @@ -919,13 +919,13 @@ void Widget::chosenRow(const ChosenRow &row) { && history->isForum() && !row.message.fullId && (!controller()->adaptive().isOneColumn() - || !history->peer->forum()->channel()->viewForumAsMessages() - || history->peer->forum()->channel()->useSubsectionTabs())) { + || !history->peer->viewForumAsMessages() + || history->peer->useSubsectionTabs())) { const auto forum = history->peer->forum(); if (controller()->shownForum().current() == forum) { controller()->closeForum(); } else if (row.newWindow) { - const auto type = forum->channel()->useSubsectionTabs() + const auto type = forum->peer()->useSubsectionTabs() ? Window::SeparateType::Chat : Window::SeparateType::Forum; controller()->showInNewWindow(Window::SeparateId(type, history)); @@ -935,7 +935,7 @@ void Widget::chosenRow(const ChosenRow &row) { Window::SectionShow( Window::SectionShow::Way::ClearStack).withChildColumn()); if (controller()->shownForum().current() == forum - && forum->channel()->viewForumAsMessages()) { + && forum->peer()->viewForumAsMessages()) { controller()->showThread( history, ShowAtUnreadMsgId, @@ -2016,24 +2016,24 @@ void Widget::refreshTopBars() { } _forumSearchRequested = false; if (_openedForum) { - const auto channel = _openedForum->channel(); - channel->updateFull(); + const auto peer = _openedForum->peer(); + peer->updateFull(); _forumReportBar = std::make_unique( controller(), this, - channel, + peer, true); _forumRequestsBar = std::make_unique( this, HistoryView::RequestsBarContentByPeer( - channel, + peer, st::historyRequestsUserpics.size, true)); _forumGroupCallBar = std::make_unique( this, HistoryView::GroupCallBarContentByPeer( - channel, + peer, st::historyGroupCallUserpics.size, true), Core::App().appDeactivatedValue()); @@ -2041,15 +2041,15 @@ void Widget::refreshTopBars() { _forumRequestsBar->barClicks( ) | rpl::start_with_next([=] { - RequestsBoxController::Start(controller(), channel); + RequestsBoxController::Start(controller(), peer); }, _forumRequestsBar->lifetime()); rpl::merge( _forumGroupCallBar->barClicks(), _forumGroupCallBar->joinClicks() ) | rpl::start_with_next([=] { - if (channel->groupCall()) { - controller()->startOrJoinGroupCall(channel); + if (peer->groupCall()) { + controller()->startOrJoinGroupCall(peer); } }, _forumGroupCallBar->lifetime()); @@ -2763,7 +2763,7 @@ void Widget::searchTopics() { _api.request(base::take(_topicSearchRequest)).cancel(); _topicSearchRequest = _api.request(MTPmessages_GetForumTopics( MTP_flags(MTPmessages_GetForumTopics::Flag::f_q), - _openedForum->channel()->input, + _openedForum->peer()->input, MTP_string(_topicSearchQuery), MTP_int(_topicSearchOffsetDate), MTP_int(_topicSearchOffsetId), @@ -3065,6 +3065,9 @@ void Widget::searchReceived( // Don't apply cached data! session().data().processUsers(data.vusers()); session().data().processChats(data.vchats()); + if (const auto peer = searchInPeer()) { + peer->processTopics(data.vtopics()); + } } process->full = true; auto list = processList(data.vmessages()); @@ -3075,6 +3078,9 @@ void Widget::searchReceived( // Don't apply cached data! session().data().processUsers(data.vusers()); session().data().processChats(data.vchats()); + if (const auto peer = searchInPeer()) { + peer->processTopics(data.vtopics()); + } } auto list = processList(data.vmessages()); const auto nextRate = data.vnext_rate(); @@ -3092,24 +3098,24 @@ void Widget::searchReceived( fullCount = data.vcount().v; return list; }, [&](const MTPDmessages_channelMessages &data) { - if (const auto peer = searchInPeer()) { - if (const auto channel = peer->asChannel()) { - channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); + if (!cacheResults) { + // Don't apply cached data! + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); + if (const auto peer = searchInPeer()) { + if (const auto channel = peer->asChannel()) { + channel->ptsReceived(data.vpts().v); + } else { + LOG(("API Error: " + "received messages.channelMessages when no channel " + "was passed! (Widget::searchReceived)")); + } + peer->processTopics(data.vtopics()); } else { LOG(("API Error: " "received messages.channelMessages when no channel " "was passed! (Widget::searchReceived)")); } - } else { - LOG(("API Error: " - "received messages.channelMessages when no channel " - "was passed! (Widget::searchReceived)")); - } - if (!cacheResults) { - // Don't apply cached data! - session().data().processUsers(data.vusers()); - session().data().processChats(data.vchats()); } auto list = processList(data.vmessages()); if (list.empty()) { @@ -3144,6 +3150,7 @@ void Widget::searchApplyEmpty( type, MTP_messages_messages( MTP_vector(), + MTP_vector(), MTP_vector(), MTP_vector()), process); @@ -3364,7 +3371,7 @@ void Widget::openChildList( controller(), Layout::Child); _childList->showForum(forum, copy); - _childListPeerId = forum->channel()->id; + _childListPeerId = forum->peer()->id; } _childListShadow = std::make_unique(this); @@ -4223,7 +4230,7 @@ PeerData *Widget::searchInPeer() const { || _searchState.tab == ChatSearchTab::PublicPosts) ? nullptr : _openedForum - ? _openedForum->channel().get() + ? _openedForum->peer().get() : _searchState.inChat.sublist() ? _searchState.inChat.sublist()->owningHistory()->peer.get() : _searchState.inChat.peer(); @@ -4359,7 +4366,7 @@ bool Widget::cancelSearch(CancelSearchOptions options) { updateForceDisplayWide(); if (clearingInChat) { if (const auto forum = controller()->shownForum().current()) { - if (forum->channel()->useSubsectionTabs()) { + if (forum->peer()->useSubsectionTabs()) { const auto id = controller()->windowId(); const auto initial = id.forum(); if (!initial) { diff --git a/Telegram/SourceFiles/history/history_unread_things.cpp b/Telegram/SourceFiles/history/history_unread_things.cpp index 1ba1678f3a..eeed5bddea 100644 --- a/Telegram/SourceFiles/history/history_unread_things.cpp +++ b/Telegram/SourceFiles/history/history_unread_things.cpp @@ -143,17 +143,19 @@ void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) { "(Proxy::addSlice)")); return 0; }, [&](const MTPDmessages_messages &data) { + history->peer->processTopics(data.vtopics()); return int(data.vmessages().v.size()); }, [&](const MTPDmessages_messagesSlice &data) { + history->peer->processTopics(data.vtopics()); return data.vcount().v; }, [&](const MTPDmessages_channelMessages &data) { if (const auto channel = history->peer->asChannel()) { channel->ptsReceived(data.vpts().v); - channel->processTopics(data.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (Proxy::addSlice)")); } + history->peer->processTopics(data.vtopics()); return data.vcount().v; }); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 831fcdae2c..9f726f5919 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -3848,6 +3848,7 @@ void HistoryWidget::messagesReceived( auto &d(messages.c_messages_messages()); _history->owner().processUsers(d.vusers()); _history->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); histList = &d.vmessages().v; count = histList->size(); } break; @@ -3855,20 +3856,21 @@ void HistoryWidget::messagesReceived( auto &d(messages.c_messages_messagesSlice()); _history->owner().processUsers(d.vusers()); _history->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); histList = &d.vmessages().v; count = d.vcount().v; } break; case mtpc_messages_channelMessages: { auto &d(messages.c_messages_channelMessages()); + _history->owner().processUsers(d.vusers()); + _history->owner().processChats(d.vchats()); if (const auto channel = peer->asChannel()) { channel->ptsReceived(d.vpts().v); - channel->processTopics(d.vtopics()); } else { LOG(("API Error: received messages.channelMessages when " "no channel was passed! (HistoryWidget::messagesReceived)")); } - _history->owner().processUsers(d.vusers()); - _history->owner().processChats(d.vchats()); + peer->processTopics(d.vtopics()); histList = &d.vmessages().v; count = d.vcount().v; } break; diff --git a/Telegram/SourceFiles/history/view/history_view_chat_preview.cpp b/Telegram/SourceFiles/history/view/history_view_chat_preview.cpp index 8242a4baa3..1e677e6caa 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_preview.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_preview.cpp @@ -352,7 +352,7 @@ void Item::setupTop() { : Ui::CreateChild( _top.get(), (topic - ? Info::Profile::NameValue(topic->channel()) + ? Info::Profile::NameValue(topic->peer()) : std::move(statusText)), st::previewStatus); if (status) { diff --git a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp index b0a48e1bdb..8553a4bd65 100644 --- a/Telegram/SourceFiles/history/view/history_view_contact_status.cpp +++ b/Telegram/SourceFiles/history/view/history_view_contact_status.cpp @@ -1110,7 +1110,9 @@ TopicReopenBar::TopicReopenBar( void TopicReopenBar::setupState() { const auto channel = _topic->channel(); - auto canToggle = (_topic->my() || channel->amCreator()) + auto canToggle = !channel + ? (rpl::single(false) | rpl::type_erased()) + : (_topic->my() || channel->amCreator()) ? (rpl::single(true) | rpl::type_erased()) : channel->adminRightsValue( ) | rpl::map([=] { return _topic->canToggleClosed(); }); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 6635e38197..1df54340f8 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1617,8 +1617,8 @@ void Element::recountThreadBarInBlocks() { const auto item = data(); const auto topic = item->topic(); const auto sublist = item->savedSublist(); - const auto parentChat = (topic && topic->channel()->useSubsectionTabs()) - ? topic->channel().get() + const auto parentChat = (topic && topic->peer()->useSubsectionTabs()) + ? topic->peer().get() : sublist ? sublist->parentChat() : nullptr; @@ -1632,7 +1632,7 @@ void Element::recountThreadBarInBlocks() { if (const auto previous = previousDisplayedInBlocks()) { const auto prev = previous->data(); if (const auto prevTopic = prev->topic()) { - Assert(prevTopic->channel() == parentChat); + Assert(prevTopic->peer() == parentChat); const auto topicRootId = topic->rootId(); if (prevTopic->rootId() == topicRootId) { return nullptr; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 023ddb1424..1b58ecd65c 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1096,7 +1096,7 @@ void Message::refreshTopicButton() { if (isAttachedToPrevious() || delegate()->elementHideTopicButton(this)) { _topicButton = nullptr; } else if (const auto topic = item->topic()) { - if (topic->channel()->useSubsectionTabs()) { + if (topic->peer()->useSubsectionTabs()) { _topicButton = nullptr; return; } diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 9ff972022d..b8144e842a 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -846,7 +846,7 @@ void TopBarWidget::setActiveChat( if (const auto topic = _activeChat.key.topic()) { Info::Profile::NameValue( - topic->channel() + topic->peer() ) | rpl::start_with_next([=](const QString &name) { _titlePeerText.setText(st::dialogsTextStyle, name); _titlePeerTextOnline = false; diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index 42f8972a0a..19b520f95a 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -79,7 +79,7 @@ PeerData *Key::peer() const { if (const auto peer = std::get_if>(&_value)) { return *peer; } else if (const auto topic = this->topic()) { - return topic->channel(); + return topic->peer(); } else if (const auto sublist = this->sublist()) { return sublist->owningHistory()->peer; } diff --git a/Telegram/SourceFiles/info/media/info_media_widget.cpp b/Telegram/SourceFiles/info/media/info_media_widget.cpp index 58d9e8e95e..6acb4dc82f 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_widget.cpp @@ -86,7 +86,7 @@ Memento::Memento(not_null peer, PeerId migratedPeerId, Type type) } Memento::Memento(not_null topic, Type type) -: Memento(topic->channel(), topic, nullptr, PeerId(), type) { +: Memento(topic->peer(), topic, nullptr, PeerId(), type) { } Memento::Memento(not_null sublist, Type type) diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index c035c092ae..211b2075c4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -2142,14 +2142,14 @@ void DetailsFiller::addShowTopicsListButton( using namespace rpl::mappers; const auto window = _controller->parentController(); - const auto channel = forum->channel(); + const auto peer = forum->peer(); auto showTopicsVisible = rpl::combine( window->adaptive().oneColumnValue(), window->shownForum().value(), _1 || (_2 != forum)); const auto callback = [=] { - if (const auto forum = channel->forum()) { - if (channel->useSubsectionTabs()) { + if (const auto forum = peer->forum()) { + if (peer->useSubsectionTabs()) { window->searchInChat(forum->history()); } else { window->showForum(forum); diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 9a3b9e4e75..ed84af77ae 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -560,7 +560,7 @@ Cover::Cover( : Cover( parent, controller, - topic->channel(), + topic->peer(), topic, Role::Info, TitleValue(topic), diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index ac25b6c436..b545585ec5 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -281,10 +281,10 @@ rpl::producer NotificationsEnabledValue( Data::TopicUpdate::Flag::Notifications ) | rpl::to_empty, topic->session().changes().peerUpdates( - topic->channel(), + topic->peer(), UpdateFlag::Notifications ) | rpl::to_empty, - topic->owner().notifySettings().defaultUpdates(topic->channel()) + topic->owner().notifySettings().defaultUpdates(topic->peer()) ) | rpl::map([=] { return !topic->owner().notifySettings().isMuted(topic); }) | rpl::distinct_until_changed(); diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp index a11face226..6ba4a1118c 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp @@ -50,7 +50,7 @@ Memento::Memento( } Memento::Memento(not_null topic) -: ContentMemento(topic->channel(), topic, nullptr, 0) { +: ContentMemento(topic->peer(), topic, nullptr, 0) { } Memento::Memento(not_null sublist) diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 5202659722..a15376135d 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -415,8 +415,12 @@ void TogglePinnedThread( controller->content()->dialogsToUp(); } } else if (const auto topic = entry->asTopic()) { + const auto channel = topic->channel(); + if (!channel) { + return; + } owner->session().api().request(MTPchannels_UpdatePinnedForumTopic( - topic->channel()->inputChannel, + channel->inputChannel, MTP_int(topic->rootId()), MTP_bool(isPinned) )).done([=](const MTPUpdates &result) { @@ -1063,6 +1067,9 @@ void Filler::addTopicLink() { return; } const auto channel = _topic->channel(); + if (!channel) { + return; + } const auto id = _topic->rootId(); const auto controller = _controller; _addAction(tr::lng_context_copy_topic_link(tr::now), [=] { @@ -1805,17 +1812,17 @@ void PeerMenuDeleteTopicWithConfirmation( void PeerMenuDeleteTopic( not_null navigation, - not_null channel, + not_null peer, MsgId rootId) { - const auto api = &channel->session().api(); + const auto api = &peer->session().api(); api->request(MTPmessages_DeleteTopicHistory( - channel->input, + peer->input, MTP_int(rootId) )).done([=](const MTPmessages_AffectedHistory &result) { - const auto offset = api->applyAffectedHistory(channel, result); + const auto offset = api->applyAffectedHistory(peer, result); if (offset > 0) { - PeerMenuDeleteTopic(navigation, channel, rootId); - } else if (const auto forum = channel->forum()) { + PeerMenuDeleteTopic(navigation, peer, rootId); + } else if (const auto forum = peer->forum()) { forum->applyTopicDeleted(rootId); } }).send(); @@ -1824,7 +1831,7 @@ void PeerMenuDeleteTopic( void PeerMenuDeleteTopic( not_null navigation, not_null topic) { - PeerMenuDeleteTopic(navigation, topic->channel(), topic->rootId()); + PeerMenuDeleteTopic(navigation, topic->peer(), topic->rootId()); } void PeerMenuShareContactBox( diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 28a40bdbdd..d1956026d2 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -623,7 +623,7 @@ void SessionNavigation::showPeerByLinkResolved( if (controller->windowId().hasChatsList() && !controller->adaptive().isOneColumn() && controller->shownForum().current() != forum - && !forum->channel()->useSubsectionTabs()) { + && !forum->peer()->useSubsectionTabs()) { controller->showForum(forum); } } @@ -1991,11 +1991,11 @@ void SessionController::showForum( const auto forced = params.forceTopicsList; if (showForumInDifferentWindow(forum, params)) { return; - } else if (!forced && forum->channel()->useSubsectionTabs()) { + } else if (!forced && forum->peer()->useSubsectionTabs()) { if (const auto active = forum->activeSubsectionThread()) { showThread(active, ShowAtUnreadMsgId, params); } else { - showPeerHistory(forum->channel(), params); + showPeerHistory(forum->peer(), params); } return; } @@ -2038,14 +2038,16 @@ void SessionController::showForum( }, _shownForumLifetime); if (!forced) { using FlagChange = Data::Flags::Change; - forum->channel()->flagsValue( - ) | rpl::start_with_next([=](FlagChange change) { - if (change.diff & ChannelDataFlag::ForumTabs) { - if (HistoryView::SubsectionTabs::UsedFor(history)) { - closeAndShowHistory(true); + if (const auto channel = forum->channel()) { + channel->flagsValue( + ) | rpl::start_with_next([=](FlagChange change) { + if (change.diff & ChannelDataFlag::ForumTabs) { + if (HistoryView::SubsectionTabs::UsedFor(history)) { + closeAndShowHistory(true); + } } - } - }, _shownForumLifetime); + }, _shownForumLifetime); + } } }