diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp index d127053c0..7f4484c47 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_utilities.h" // Ui::Text::ToUpper #include "boxes/peer_list_box.h" #include "ui/boxes/confirm_box.h" +#include "ui/toasts/common_toasts.h" #include "boxes/add_contact_box.h" #include "apiwrap.h" #include "main/main_session.h" @@ -32,6 +33,7 @@ constexpr auto kEnableSearchRowsCount = 10; class Controller : public PeerListController, public base::has_weak_ptr { public: Controller( + not_null navigation, not_null channel, ChannelData *chat, const std::vector> &chats, @@ -47,6 +49,7 @@ private: void choose(not_null chat); void choose(not_null chat); + not_null _navigation; not_null _channel; ChannelData *_chat = nullptr; std::vector> _chats; @@ -59,12 +62,14 @@ private: }; Controller::Controller( + not_null navigation, not_null channel, ChannelData *chat, const std::vector> &chats, Fn callback, Fn)> showHistoryCallback) -: _channel(channel) +: _navigation(navigation) +, _channel(channel) , _chat(chat) , _chats(std::move(chats)) , _callback(std::move(callback)) @@ -131,6 +136,10 @@ void Controller::rowClicked(not_null row) { } void Controller::choose(not_null chat) { + if (chat->isForum()) { + ShowForumForDiscussionError(_navigation); + return; + } auto text = tr::lng_manage_discussion_group_sure( tr::now, lt_group, @@ -324,6 +333,7 @@ object_ptr EditLinkedChatBox( ShowAtUnreadMsgId); }; auto controller = std::make_unique( + navigation, channel, chat, std::move(chats), @@ -362,3 +372,13 @@ object_ptr EditLinkedChatBox( canEdit, callback); } + +void ShowForumForDiscussionError( + not_null navigation) { + Ui::ShowMultilineToast({ + .parentOverride = Window::Show(navigation).toastParent(), + .text = tr::lng_forum_topics_no_discussion( + tr::now, + Ui::Text::RichLangValue), + }); +} diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h index cf36d107b..ce7c50703 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h @@ -29,3 +29,6 @@ object_ptr EditLinkedChatBox( not_null channel, std::vector> &&chats, Fn callback); + +void ShowForumForDiscussionError( + not_null navigation); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index ec69390b2..99e7ae3e8 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -39,10 +39,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" #include "mtproto/sender.h" +#include "main/main_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" #include "settings/settings_common.h" #include "ui/rp_widget.h" #include "ui/special_buttons.h" #include "ui/toast/toast.h" +#include "ui/toasts/common_toasts.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" @@ -67,6 +72,12 @@ namespace { }); } +[[nodiscard]] int EnableForumMinMembers(not_null peer) { + return peer->session().account().appConfig().get( + u"forum_upgrade_participants_min"_q, + 200); +} + void AddSkip( not_null container, int top = st::editPeerTopButtonsLayoutSkip, @@ -253,6 +264,8 @@ private: Ui::UserpicButton *photo = nullptr; rpl::lifetime initialPhotoImageWaiting; Ui::VerticalLayout *buttonsLayout = nullptr; + Ui::SettingsButton *forumToggle = nullptr; + bool forumToggleLocked = false; Ui::SlideWrap<> *historyVisibilityWrap = nullptr; }; struct Saving { @@ -279,6 +292,7 @@ private: [[nodiscard]] bool canEditInformation() const; [[nodiscard]] bool canEditReactions() const; void refreshHistoryVisibility(); + void refreshForumToggleLocked(); void showEditPeerTypeBox( std::optional> error = {}); void showEditLinkedChatBox(); @@ -614,7 +628,8 @@ void Controller::refreshHistoryVisibility() { _controls.historyVisibilityWrap->toggle( (!withUsername && !_channelHasLocationOriginalValue - && (!_linkedChatSavedValue || !*_linkedChatSavedValue)), + && (!_linkedChatSavedValue || !*_linkedChatSavedValue) + && (!_forumSavedValue || !*_forumSavedValue)), anim::type::instant); } @@ -645,6 +660,11 @@ void Controller::showEditPeerTypeBox( void Controller::showEditLinkedChatBox() { Expects(_peer->isChannel()); + if (_forumSavedValue && *_forumSavedValue) { + ShowForumForDiscussionError(_navigation); + return; + } + const auto box = std::make_shared>(); const auto channel = _peer->asChannel(); const auto callback = [=](ChannelData *result) { @@ -654,6 +674,7 @@ void Controller::showEditLinkedChatBox() { *_linkedChatSavedValue = result; _linkedChatUpdates.fire_copy(result); refreshHistoryVisibility(); + refreshForumToggleLocked(); }; const auto canEdit = channel->isBroadcast() ? channel->canEditInformation() @@ -675,8 +696,14 @@ void Controller::showEditLinkedChatBox() { } else if (!canEdit || _linkedChatsRequestId) { return; } else if (channel->isMegagroup()) { - // Restore original linked channel. - callback(_linkedChatOriginalValue); + if (_forumSavedValue + && *_forumSavedValue + && _linkedChatOriginalValue) { + ShowForumForDiscussionError(_navigation); + } else { + // Restore original linked channel. + callback(_linkedChatOriginalValue); + } return; } _linkedChatsRequestId = _api.request( @@ -817,22 +844,58 @@ void Controller::fillLinkedChatButton() { void Controller::fillForumButton() { Expects(_controls.buttonsLayout != nullptr); - const auto channel = _peer->asChannel(); - if (!channel || !channel->amCreator()) { - return; - } - - AddButtonWithText( - _controls.buttonsLayout, - tr::lng_forum_topics_switch(), - rpl::single(QString()), - [] {}, - { &st::settingsIconGroup, Settings::kIconPurple } - )->toggleOn(rpl::single(channel->isForum()) + const auto button = _controls.forumToggle = _controls.buttonsLayout->add( + EditPeerInfoBox::CreateButton( + _controls.buttonsLayout, + tr::lng_forum_topics_switch(), + rpl::single(QString()), + [] {}, + st::manageGroupTopicsButton, + { &st::settingsIconGroup, Settings::kIconPurple })); + const auto unlocks = std::make_shared>(); + button->toggleOn( + rpl::single(_peer->isForum()) | rpl::then(unlocks->events()) )->toggledValue( ) | rpl::start_with_next([=](bool toggled) { - _forumSavedValue = toggled; + if (_controls.forumToggleLocked && toggled) { + unlocks->fire(false); + if (_linkedChatSavedValue && *_linkedChatSavedValue) { + ShowForumForDiscussionError(_navigation); + } else { + Ui::ShowMultilineToast({ + .parentOverride = Window::Show( + _navigation).toastParent(), + .text = tr::lng_forum_topics_not_enough( + tr::now, + lt_count, + EnableForumMinMembers(_peer), + Ui::Text::RichLangValue), + }); + } + } else { + _forumSavedValue = toggled; + if (toggled) { + _savingData.hiddenPreHistory = false; + } + refreshHistoryVisibility(); + } }, _controls.buttonsLayout->lifetime()); + refreshForumToggleLocked(); +} + +void Controller::refreshForumToggleLocked() { + if (!_controls.forumToggle) { + return; + } + const auto limit = EnableForumMinMembers(_peer); + const auto chat = _peer->asChat(); + const auto channel = _peer->asChannel(); + const auto notenough = !_peer->isForum() + && ((chat ? chat->count : channel->membersCount()) < limit); + const auto linked = _linkedChatSavedValue + && *_linkedChatSavedValue; + const auto locked = _controls.forumToggleLocked = notenough || linked; + _controls.forumToggle->setToggleLocked(locked); } void Controller::fillSignaturesButton() { @@ -943,8 +1006,8 @@ void Controller::fillManageSection() { : chat->canEditPreHistoryHidden(); }(); const auto canEditForum = isChannel - && channel->isMegagroup() - && channel->canEditInformation(); + ? (channel->isMegagroup() && channel->amCreator()) + : chat->amCreator(); const auto canEditPermissions = [&] { return isChannel @@ -1703,9 +1766,20 @@ void Controller::togglePreHistoryHidden( void Controller::saveForum() { const auto channel = _peer->asChannel(); if (!_savingData.forum - || !channel - || *_savingData.forum == channel->isForum()) { + || *_savingData.forum == _peer->isForum()) { return continueSave(); + } else if (!channel) { + const auto saveForChannel = [=](not_null channel) { + if (_peer->asChannel() == channel) { + saveForum(); + } else { + cancelSave(); + } + }; + _peer->session().api().migrateChat( + _peer->asChat(), + crl::guard(this, saveForChannel)); + return; } _api.request(MTPchannels_ToggleForum( channel->inputChannel, diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 5a1779b5c..d55449ece 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -111,7 +111,7 @@ void Forum::preloadTopics() { } void Forum::reloadTopics() { - _allLoaded = false; + _topicsList.setLoaded(false); session().api().request(base::take(_requestId)).cancel(); _offsetDate = 0; _offsetId = _offsetTopicId = 0; @@ -124,7 +124,7 @@ void Forum::reloadTopics() { } void Forum::requestTopics() { - if (_allLoaded || _requestId) { + if (_topicsList.loaded() || _requestId) { return; } const auto firstLoad = !_offsetDate; @@ -141,13 +141,13 @@ void Forum::requestTopics() { applyReceivedTopics(result, true); _requestId = 0; _chatsListChanges.fire({}); - if (_allLoaded) { + if (_topicsList.loaded()) { _chatsListLoadedEvents.fire({}); } requestSomeStale(); }).fail([=](const MTP::Error &error) { - _allLoaded = true; _requestId = 0; + _topicsList.setLoaded(); if (error.type() == u"CHANNEL_FORUM_MISSING"_q) { const auto flags = channel()->flags() & ~ChannelDataFlag::Forum; channel()->setFlags(flags); @@ -215,7 +215,7 @@ void Forum::applyReceivedTopics( } if (updateOffset && (list.isEmpty() || list.size() == data.vcount().v)) { - _allLoaded = true; + _topicsList.setLoaded(); } if (!_staleRootIds.empty()) { requestSomeStale(); diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index 04aa3f896..da41ad9f5 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -103,7 +103,6 @@ private: TimeId _offsetDate = 0; MsgId _offsetId = 0; MsgId _offsetTopicId = 0; - bool _allLoaded = false; base::flat_set _creatingRootIds; diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 605769cd2..6520f37e5 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -567,10 +567,11 @@ peerPermissionsButton: SettingsCountButton(managePeerButton) { iconPosition: point(24px, 5px); } +manageGroupButtonInner: SettingsButton(infoProfileButton) { + padding: margins(60px, 10px, 24px, 8px); +} manageGroupButton: SettingsCountButton(managePeerButton) { - button: SettingsButton(infoProfileButton) { - padding: margins(60px, 10px, 24px, 8px); - } + button: manageGroupButtonInner; labelPosition: point(22px, 12px); iconPosition: point(20px, 4px); } @@ -579,6 +580,16 @@ manageGroupTopButtonWithText: SettingsCountButton(manageGroupButton) { labelPosition: point(22px, 10px); iconPosition: point(0px, 0px); } +manageGroupTopicsButton: SettingsCountButton(manageGroupTopButtonWithText) { + button: SettingsButton(manageGroupButtonInner) { + toggle: Toggle(infoProfileToggle) { + lockIcon: icon {{ "info/info_rights_lock", menuIconFg }}; + } + toggleOver: Toggle(infoProfileToggleOver) { + lockIcon: icon {{ "info/info_rights_lock", menuIconFgOver }}; + } + } +} manageDeleteGroupButton: SettingsCountButton(manageGroupTopButtonWithText) { button: SettingsButton(infoProfileButton) { diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 7f1dd3c35..865056eec 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 7f1dd3c351f534d0564c41376176eb0cd1be4184 +Subproject commit 865056eec8986bfbdc7f1194ef16ea9db6243742