diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1aa436225..f6d6c4991 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4170,6 +4170,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_forum_create_topic" = "Create topic"; "lng_forum_discard_sure" = "Are you sure you want to discard this topic?"; "lng_forum_view_as_messages" = "View as Messages"; +"lng_forum_view_as_topics" = "View as Topics"; "lng_forum_no_messages" = "No messages"; "lng_forum_messages#one" = "{count} message"; "lng_forum_messages#other" = "{count} messages"; diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 064f410c5..aeca3eb70 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2326,6 +2326,14 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateChannelViewForumAsMessages: { + const auto &d = update.c_updateChannelViewForumAsMessages(); + const auto id = ChannelId(d.vchannel_id()); + if (const auto channel = session().data().channelLoaded(id)) { + channel->setViewAsMessagesFlag(mtpIsTrue(d.venabled())); + } + } break; + // Pinned message. case mtpc_updatePinnedMessages: { const auto &d = update.c_updatePinnedMessages(); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 5daff7e17..eab1be564 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -475,6 +475,14 @@ void ChannelData::applyEditBanned( session().changes().peerUpdated(this, flags); } +void ChannelData::setViewAsMessagesFlag(bool enabled) { + if (viewForumAsMessages() == enabled) { + return; + } + setFlags((flags() & ~Flag::ViewAsMessages) + | (enabled ? Flag::ViewAsMessages : Flag())); +} + void ChannelData::markForbidden() { owner().processChat(MTP_channelForbidden( MTP_flags(isMegagroup() @@ -998,7 +1006,8 @@ void ApplyChannelUpdate( | Flag::AntiSpam | Flag::Location | Flag::ParticipantsHidden - | Flag::CanGetStatistics; + | Flag::CanGetStatistics + | Flag::ViewAsMessages; channel->setFlags((channel->flags() & ~mask) | (update.is_can_set_username() ? Flag::CanSetUsername : Flag()) | (update.is_can_view_participants() @@ -1011,7 +1020,10 @@ void ApplyChannelUpdate( | (update.is_participants_hidden() ? Flag::ParticipantsHidden : Flag()) - | (update.is_can_view_stats() ? Flag::CanGetStatistics : Flag())); + | (update.is_can_view_stats() ? Flag::CanGetStatistics : Flag()) + | (update.is_view_forum_as_messages() + ? Flag::ViewAsMessages + : Flag())); channel->setUserpicPhoto(update.vchat_photo()); if (const auto migratedFrom = update.vmigrated_from_chat_id()) { channel->addFlags(Flag::Megagroup); diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index bdf0f4205..a52c4d969 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -63,6 +63,7 @@ enum class ChannelDataFlag { HasActiveStories = (1 << 27), HasUnreadStories = (1 << 28), CanGetStatistics = (1 << 29), + ViewAsMessages = (1 << 30), }; inline constexpr bool is_flag_type(ChannelDataFlag) { return true; }; using ChannelDataFlags = base::flags; @@ -233,6 +234,9 @@ public: [[nodiscard]] bool hasStoriesHidden() const { return flags() & Flag::StoriesHidden; } + [[nodiscard]] bool viewForumAsMessages() const { + return flags() & Flag::ViewAsMessages; + } [[nodiscard]] static ChatRestrictionsInfo KickedRestrictedRights( not_null participant); @@ -249,6 +253,7 @@ public: not_null participant, ChatRestrictionsInfo oldRights, ChatRestrictionsInfo newRights); + void setViewAsMessagesFlag(bool enabled); void markForbidden(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index bc124d71f..6491b6684 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -4545,6 +4545,25 @@ void Session::applyStatsDcId( } } +void Session::saveViewAsMessages( + not_null forum, + bool viewAsMessages) { + const auto channel = forum->channel(); + if (const auto requestId = _viewAsMessagesRequests.take(channel)) { + _session->api().request(*requestId).cancel(); + } + _viewAsMessagesRequests[channel] = _session->api().request( + MTPchannels_ToggleViewForumAsMessages( + channel->inputChannel, + MTP_bool(viewAsMessages)) + ).done([=] { + _viewAsMessagesRequests.remove(channel); + }).fail([=] { + _viewAsMessagesRequests.remove(channel); + }).send(); + channel->setViewAsMessagesFlag(viewAsMessages); +} + void Session::webViewResultSent(WebViewResultSent &&sent) { return _webViewResultSent.fire(std::move(sent)); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index df6dc5019..47e4a4012 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -727,6 +727,8 @@ public: void webViewResultSent(WebViewResultSent &&sent); [[nodiscard]] rpl::producer webViewResultSent() const; + void saveViewAsMessages(not_null forum, bool viewAsMessages); + [[nodiscard]] auto peerDecorationsUpdated() const -> rpl::producer>; @@ -1022,6 +1024,9 @@ private: rpl::event_stream _webViewResultSent; rpl::event_stream> _peerDecorationsUpdated; + base::flat_map< + not_null, + mtpRequestId> _viewAsMessagesRequests; Groups _groups; const std::unique_ptr _chatsFilters; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index a6863e357..5a9e98a69 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1251,7 +1251,8 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { const auto selectedTopicJump = selected && selected->lookupIsInTopicJump( local.x(), - mouseY - offset - selected->top()); + mouseY - offset - selected->top()) + && _controller->adaptive().isOneColumn(); if (_collapsedSelected != collapsedSelected || _selected != selected || _selectedTopicJump != selectedTopicJump) { @@ -1293,7 +1294,8 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { const auto selectedTopicJump = (filteredSelected >= 0) && _filterResults[filteredSelected].row->lookupIsInTopicJump( local.x(), - mouseY - skip - _filterResults[filteredSelected].top); + mouseY - skip - _filterResults[filteredSelected].top) + && _controller->adaptive().isOneColumn(); if (_filteredSelected != filteredSelected || _selectedTopicJump != selectedTopicJump) { updateSelectedRow(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 7bb0fb805..e8a04121d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -520,18 +520,37 @@ void Widget::chosenRow(const ChosenRow &row) { } return; } else if (const auto topic = row.key.topic()) { + session().data().saveViewAsMessages(topic->forum(), false); controller()->showThread( topic, row.message.fullId.msg, Window::SectionShow::Way::ClearStack); - } else if (history && history->isForum() && !row.message.fullId) { + } else if (history + && history->isForum() + && !row.message.fullId + && (!controller()->adaptive().isOneColumn() + || !history->peer->forum()->channel()->viewForumAsMessages())) { const auto forum = history->peer->forum(); if (controller()->shownForum().current() == forum) { controller()->closeForum(); - } else { - controller()->showForum( - forum, - Window::SectionShow().withChildColumn()); + return; + } + controller()->showForum( + forum, + Window::SectionShow().withChildColumn()); + if (forum->channel()->viewForumAsMessages()) { + controller()->showThread( + history, + ShowAtUnreadMsgId, + Window::SectionShow::Way::ClearStack); + } else if (!controller()->adaptive().isOneColumn()) { + const auto item = history->chatListMessage(); + if (const auto topic = item ? item->topic() : nullptr) { + controller()->showThread( + topic, + ShowAtUnreadMsgId, + Window::SectionShow::Way::ClearStack); + } } return; } else if (history) { diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index e5c03f37d..c9ede3a95 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2808,6 +2808,7 @@ void History::applyDialog( } } } + channel->setViewAsMessagesFlag(data.is_view_forum_as_messages()); } owner().notifySettings().apply( MTP_notifyPeer(data.vpeer()), diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 96fda3d43..a887b3f5d 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -281,6 +281,7 @@ private: void addGiftPremium(); void addCreateTopic(); void addViewAsMessages(); + void addViewAsTopics(); void addSearchTopics(); void addDeleteTopic(); void addVideoChat(); @@ -1147,10 +1148,29 @@ void Filler::addViewAsMessages() { const auto peer = _peer; const auto controller = _controller; _addAction(tr::lng_forum_view_as_messages(tr::now), [=] { + if (const auto forum = peer->forum()) { + peer->owner().saveViewAsMessages(forum, true); + } controller->showPeerHistory(peer->id); }, &st::menuIconViewReplies); } +void Filler::addViewAsTopics() { + if (!_peer + || !_peer->isForum() + || !_controller->adaptive().isOneColumn()) { + return; + } + const auto peer = _peer; + const auto controller = _controller; + _addAction(tr::lng_forum_view_as_topics(tr::now), [=] { + if (const auto forum = peer->forum()) { + peer->owner().saveViewAsMessages(forum, false); + controller->showForum(forum); + } + }, &st::menuIconViewReplies); +} + void Filler::addSearchTopics() { const auto forum = _peer ? _peer->forum() : nullptr; if (!forum) { @@ -1235,6 +1255,7 @@ void Filler::fillContextMenuActions() { void Filler::fillHistoryActions() { addToggleMuteSubmenu(true); addInfo(); + addViewAsTopics(); addStoryArchive(); addSupportInfo(); addManageChat();