diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 82a31ced1..0037d48c7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3558,9 +3558,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_toast_add" = "{chat} added to {folder} folder"; "lng_filters_toast_remove" = "{chat} removed from {folder} folder"; -"lng_filters_link" = "Invite links"; +"lng_filters_delete_sure" = "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder."; +"lng_filters_link" = "Share Folder"; +"lng_filters_link_has" = "Invite links"; "lng_filters_link_badge" = "New"; -"lng_filters_link_create" = "Share Folder"; +"lng_filters_link_create" = "Create an Invite Link"; "lng_filters_link_cant" = "No way to share folders with chat types or excluded chats."; "lng_filters_link_about" = "Share access to some of this folder's groups and channels with others."; "lng_filters_link_about_many" = "Create more links to set up different access levels for different people."; @@ -3577,6 +3579,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_link_noadmin_status" = "you can't invite others here"; "lng_filters_link_noadmin_group_error" = "You don't have the admin rights to share invite links to this group chat."; "lng_filters_link_noadmin_channel_error" = "You don't have the admin rights to share invite links to this channel."; +"lng_filters_link_already_group" = "you are already a member"; +"lng_filters_link_already_channel" = "you are already subscribed"; "lng_filters_link_chats_about" = "Select groups and channels that you want everyone who adds the folder via invite link to join."; "lng_filters_link_no_about" = "There are no chats in this folder that you can share with others."; "lng_filters_link_chats_no" = "These chats cannot be shared"; @@ -3604,8 +3608,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_by_link_quit#other" = "{count} chats to quit"; "lng_filters_by_link_select" = "Select All"; "lng_filters_by_link_deselect" = "Deselect All"; +"lng_filters_by_link_about_quit" = "You can deselect the chats you don't want to quit."; "lng_filters_by_link_remove_button" = "Remove Folder"; "lng_filters_by_link_quit_button" = "Remove Folder and Chats"; +"lng_filters_added_title" = "Folder {folder} Added"; +"lng_filters_added_also#one" = "You also joined {count} chat."; +"lng_filters_added_also#other" = "You also joined {count} chats."; +"lng_filters_updated_title" = "Folder {folder} Updated"; +"lng_filters_updated_also#one" = "You have joined {count} new chat."; +"lng_filters_updated_also#other" = "You have joined {count} new chats."; "lng_filters_bar_you_can#one" = "You can join {count} new chat"; "lng_filters_bar_you_can#other" = "You can join {count} new chats"; "lng_filters_bar_view" = "Click here to view them"; diff --git a/Telegram/SourceFiles/api/api_chat_filters.cpp b/Telegram/SourceFiles/api/api_chat_filters.cpp index 03149b6e3..332afd22f 100644 --- a/Telegram/SourceFiles/api/api_chat_filters.cpp +++ b/Telegram/SourceFiles/api/api_chat_filters.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "boxes/peer_list_box.h" +#include "boxes/filters/edit_filter_links.h" // FilterChatStatusText #include "core/application.h" #include "data/data_chat_filters.h" #include "data/data_peer.h" @@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_utilities.h" #include "ui/toasts/common_toasts.h" #include "ui/widgets/buttons.h" +#include "ui/filter_icons.h" #include "window/window_session_controller.h" #include "styles/style_filter_icons.h" #include "styles/style_layers.h" @@ -41,10 +43,9 @@ public: ToggleChatsController( not_null window, ToggleAction action, - const QString &slug, - FilterId filterId, const QString &title, - std::vector> chats); + std::vector> chats, + std::vector> additional); void prepare() override; void rowClicked(not_null row) override; @@ -63,10 +64,9 @@ private: Ui::RpWidget *_addedTopWidget = nullptr; ToggleAction _action = ToggleAction::Adding; - QString _slug; - FilterId _filterId = 0; QString _filterTitle; std::vector> _chats; + std::vector> _additional; rpl::variable>> _selected; base::unique_qptr _menu; @@ -128,13 +128,18 @@ void InitFilterLinkHeader( Fn setAddedTopHeight, Ui::FilterLinkHeaderType type, const QString &title, + const QString &iconEmoji, rpl::producer count) { + const auto icon = Ui::LookupFilterIcon( + Ui::LookupFilterIconByEmoji( + iconEmoji + ).value_or(Ui::FilterIcon::Custom)).active; auto header = Ui::MakeFilterLinkHeader(box, { .type = type, .title = TitleText(type)(tr::now), .about = AboutText(type, title), .folderTitle = title, - .folderIcon = &st::foldersCustomActive, + .folderIcon = icon, .badge = (type == Ui::FilterLinkHeaderType::AddingChats ? std::move(count) : rpl::single(0)), @@ -220,16 +225,14 @@ void ImportInvite( ToggleChatsController::ToggleChatsController( not_null window, ToggleAction action, - const QString &slug, - FilterId filterId, const QString &title, - std::vector> chats) + std::vector> chats, + std::vector> additional) : _window(window) , _action(action) -, _slug(slug) -, _filterId(filterId) , _filterTitle(title) -, _chats(std::move(chats)) { +, _chats(std::move(chats)) +, _additional(std::move(additional)) { setStyleOverrides(&st::filterLinkChatsList); } @@ -237,12 +240,34 @@ void ToggleChatsController::prepare() { setupAboveWidget(); setupBelowWidget(); auto selected = base::flat_set>(); - for (const auto &peer : _chats) { + const auto add = [&](not_null peer, bool additional = false) { auto row = std::make_unique(peer); + if (delegate()->peerListFindRow(peer->id.value)) { + return; + } const auto raw = row.get(); delegate()->peerListAppendRow(std::move(row)); - delegate()->peerListSetRowChecked(raw, true); - selected.emplace(peer); + if (!additional || _action == ToggleAction::Removing) { + if (const auto status = FilterChatStatusText(peer) + ; !status.isEmpty()) { + raw->setCustomStatus(status); + } + } + if (!additional) { + delegate()->peerListSetRowChecked(raw, true); + selected.emplace(peer); + } else if (_action == ToggleAction::Adding) { + raw->setDisabledState(PeerListRow::State::DisabledChecked); + raw->setCustomStatus(peer->isBroadcast() + ? tr::lng_filters_link_already_channel(tr::now) + : tr::lng_filters_link_already_group(tr::now)); + } + }; + for (const auto &peer : _chats) { + add(peer); + } + for (const auto &peer : _additional) { + add(peer, true); } delegate()->peerListRefreshRows(); _selected = std::move(selected); @@ -269,23 +294,51 @@ void ToggleChatsController::setupAboveWidget() { _addedTopWidget = container->add(object_ptr(container)); AddDivider(container); + const auto totalCount = [&] { + if (_chats.empty()) { + return _additional.size(); + } else if (_additional.empty()) { + return _chats.size(); + } + auto result = _chats.size(); + for (const auto &peer : _additional) { + if (!ranges::contains(_chats, peer)) { + ++result; + } + } + return result; + }; + const auto count = (_action == ToggleAction::Removing) + ? totalCount() + : _chats.empty() + ? _additional.size() + : _chats.size(); AddSubsectionTitle( container, - tr::lng_filters_by_link_join( - lt_count, - rpl::single(float64(_chats.size()))), + (_action == ToggleAction::Removing + ? tr::lng_filters_by_link_quit + : _chats.empty() + ? tr::lng_filters_by_link_in + : tr::lng_filters_by_link_join)( + lt_count, + rpl::single(float64(count))), st::filterLinkSubsectionTitlePadding); delegate()->peerListSetAboveWidget(std::move(wrap)); } void ToggleChatsController::setupBelowWidget() { + if (_chats.empty()) { + return; + } delegate()->peerListSetBelowWidget( object_ptr( (QWidget*)nullptr, object_ptr( (QWidget*)nullptr, - tr::lng_filters_by_link_about(tr::now), + (_action == ToggleAction::Removing + ? tr::lng_filters_by_link_about_quit + : tr::lng_filters_by_link_about)(tr::now), st::boxDividerLabel), st::settingsDividerLabelPadding)); } @@ -305,12 +358,40 @@ void ToggleChatsController::setAddedTopHeight(int addedTopHeight) { _addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight); } +void ShowImportToast( + base::weak_ptr weak, + const QString &title, + Ui::FilterLinkHeaderType type, + int added) { + const auto strong = weak.get(); + if (!strong) { + return; + } + const auto created = (type == Ui::FilterLinkHeaderType::AddingFilter); + const auto phrase = created + ? tr::lng_filters_added_title + : tr::lng_filters_updated_title; + auto text = Ui::Text::Bold(phrase(tr::now, lt_folder, title)); + if (added > 0) { + const auto phrase = created + ? tr::lng_filters_added_also + : tr::lng_filters_updated_also; + text.append('\n').append(phrase(tr::now, lt_count, added)); + } + Ui::ShowMultilineToast({ + .parentOverride = Window::Show(strong).toastParent(), + .text = { std::move(text) }, + }); +} + void ProcessFilterInvite( base::weak_ptr weak, const QString &slug, FilterId filterId, const QString &title, - std::vector> peers) { + const QString &iconEmoji, + std::vector> peers, + std::vector> already) { const auto strong = weak.get(); if (!strong) { return; @@ -323,19 +404,21 @@ void ProcessFilterInvite( }); return; } + const auto fullyAdded = (peers.empty() && filterId); auto controller = std::make_unique( strong, ToggleAction::Adding, - slug, - filterId, title, - std::move(peers)); + std::move(peers), + std::move(already)); const auto raw = controller.get(); auto initBox = [=](not_null box) { box->setStyle(st::filterInviteBox); using Type = Ui::FilterLinkHeaderType; - const auto type = !filterId + const auto type = fullyAdded + ? Type::AllAdded + : !filterId ? Type::AddingFilter : Type::AddingChats; auto badge = raw->selectedValue( @@ -344,7 +427,7 @@ void ProcessFilterInvite( }); InitFilterLinkHeader(box, [=](int addedTopHeight) { raw->setAddedTopHeight(addedTopHeight); - }, type, title, rpl::duplicate(badge)); + }, type, title, iconEmoji, rpl::duplicate(badge)); auto owned = Ui::FilterLinkProcessButton( box, @@ -380,6 +463,7 @@ void ProcessFilterInvite( } else if (!state->importing) { state->importing = true; ImportInvite(weak, slug, peers, crl::guard(box, [=] { + ShowImportToast(weak, title, type, peers.size()); box->closeBox(); }), crl::guard(box, [=] { state->importing = false; @@ -396,7 +480,8 @@ void ProcessFilterInvite( base::weak_ptr weak, const QString &slug, FilterId filterId, - std::vector> peers) { + std::vector> peers, + std::vector> already) { const auto strong = weak.get(); if (!strong) { return; @@ -411,7 +496,14 @@ void ProcessFilterInvite( }); return; } - ProcessFilterInvite(weak, slug, filterId, it->title(), std::move(peers)); + ProcessFilterInvite( + weak, + slug, + filterId, + it->title(), + it->iconEmoji(), + std::move(peers), + std::move(already)); } } // namespace @@ -441,6 +533,7 @@ void CheckFilterInvite( return; } auto title = QString(); + auto iconEmoji = QString(); auto filterId = FilterId(); auto peers = std::vector>(); auto already = std::vector>(); @@ -459,6 +552,7 @@ void CheckFilterInvite( }; result.match([&](const MTPDcommunities_communityInvite &data) { title = qs(data.vtitle()); + iconEmoji = data.vemoticon().value_or_empty(); peers = parseList(data.vpeers()); }, [&](const MTPDcommunities_communityInviteAlready &data) { filterId = data.vfilter_id().v; @@ -477,20 +571,103 @@ void CheckFilterInvite( owner.chatsFilters().changed( ) | rpl::start_with_next([=] { lifetime->destroy(); - ProcessFilterInvite(weak, slug, filterId, std::move(peers)); + ProcessFilterInvite( + weak, + slug, + filterId, + std::move(peers), + std::move(already)); }, *lifetime); owner.chatsFilters().reload(); } else if (filterId) { - ProcessFilterInvite(weak, slug, filterId, std::move(peers)); + ProcessFilterInvite( + weak, + slug, + filterId, + std::move(peers), + std::move(already)); } else { - ProcessFilterInvite(weak, slug, filterId, title, std::move(peers)); + ProcessFilterInvite( + weak, + slug, + filterId, + title, + iconEmoji, + std::move(peers), + std::move(already)); } }, [=](const MTP::Error &error) { if (error.code() != 400) { return; } - ProcessFilterInvite(weak, slug, FilterId(), QString(), {}); + ProcessFilterInvite(weak, slug, {}, {}, {}, {}, {}); }); } +void ProcessFilterRemove( + base::weak_ptr weak, + const QString &title, + const QString &iconEmoji, + std::vector> all, + std::vector> suggest, + Fn>)> done) { + const auto strong = weak.get(); + if (!strong) { + return; + } + Core::App().hideMediaView(); + if (all.empty() && suggest.empty()) { + done({}); + return; + } + auto controller = std::make_unique( + strong, + ToggleAction::Removing, + title, + std::move(suggest), + std::move(all)); + const auto raw = controller.get(); + auto initBox = [=](not_null box) { + box->setStyle(st::filterInviteBox); + + const auto type = Ui::FilterLinkHeaderType::Removing; + auto badge = raw->selectedValue( + ) | rpl::map([=](const base::flat_set> &peers) { + return int(peers.size()); + }); + InitFilterLinkHeader(box, [=](int addedTopHeight) { + raw->setAddedTopHeight(addedTopHeight); + }, type, title, iconEmoji, rpl::single(0)); + + auto owned = Ui::FilterLinkProcessButton( + box, + type, + title, + std::move(badge)); + + const auto button = owned.data(); + box->widthValue( + ) | rpl::start_with_next([=](int width) { + const auto &padding = st::filterInviteBox.buttonPadding; + button->resizeToWidth(width + - padding.left() + - padding.right()); + button->moveToLeft(padding.left(), padding.top()); + }, button->lifetime()); + + box->addButton(std::move(owned)); + + raw->selectedValue( + ) | rpl::start_with_next([=]( + base::flat_set> &&peers) { + button->setClickedCallback([=] { + done(peers | ranges::to_vector); + box->closeBox(); + }); + }, box->lifetime()); + }; + strong->show( + Box(std::move(controller), std::move(initBox))); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_chat_filters.h b/Telegram/SourceFiles/api/api_chat_filters.h index 99fce06a2..7691d899b 100644 --- a/Telegram/SourceFiles/api/api_chat_filters.h +++ b/Telegram/SourceFiles/api/api_chat_filters.h @@ -25,4 +25,12 @@ void CheckFilterInvite( not_null controller, const QString &slug); +void ProcessFilterRemove( + base::weak_ptr weak, + const QString &title, + const QString &iconEmoji, + std::vector> all, + std::vector> suggest, + Fn>)> done); + } // namespace Api diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp index 9c519991f..6bbded27c 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp @@ -706,7 +706,16 @@ void EditFilterBox( return result; }; - AddSubsectionTitle(content, tr::lng_filters_link()); + AddSubsectionTitle( + content, + rpl::conditional( + state->hasLinks.value(), + tr::lng_filters_link_has(), + tr::lng_filters_link())); + + state->hasLinks.changes() | rpl::start_with_next([=] { + content->resizeToWidth(content->widthNoMargins()); + }, content->lifetime()); if (filter.community()) { window->session().data().chatsFilters().reloadCommunityLinks( diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp index 0f7333a02..0aee58f6d 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp @@ -679,26 +679,12 @@ void LinkController::prepare() { setupAboveWidget(); setupBelowWidget(); - const auto countStatus = [&](not_null peer) { - if (const auto chat = peer->asChat()) { - if (const auto count = chat->count; count > 0) { - return tr::lng_chat_status_members(tr::now, lt_count, count); - } - } else if (const auto channel = peer->asChannel()) { - if (channel->membersCountKnown()) { - return (channel->isBroadcast() - ? tr::lng_chat_status_subscribers - : tr::lng_chat_status_members)( - tr::now, - lt_count, - channel->membersCount()); - } - } - return QString(); - }; for (const auto &history : _data.chats) { const auto peer = history->peer; - auto row = std::make_unique(peer, countStatus(peer), false); + auto row = std::make_unique( + peer, + FilterChatStatusText(peer), + false); const auto raw = row.get(); delegate()->peerListAppendRow(std::move(row)); delegate()->peerListSetRowChecked(raw, true); @@ -712,7 +698,7 @@ void LinkController::prepare() { const auto error = ErrorForSharing(history); auto row = std::make_unique( peer, - error ? error->status : countStatus(peer), + error ? error->status : FilterChatStatusText(peer), error.has_value()); const auto raw = row.get(); delegate()->peerListAppendRow(std::move(row)); @@ -1160,6 +1146,24 @@ object_ptr ShowLinkBox( return Box(std::move(controller), std::move(initBox)); } +QString FilterChatStatusText(not_null peer) { + if (const auto chat = peer->asChat()) { + if (const auto count = chat->count; count > 0) { + return tr::lng_chat_status_members(tr::now, lt_count, count); + } + } else if (const auto channel = peer->asChannel()) { + if (channel->membersCountKnown()) { + return (channel->isBroadcast() + ? tr::lng_chat_status_subscribers + : tr::lng_chat_status_members)( + tr::now, + lt_count, + channel->membersCount()); + } + } + return QString(); +} + void SetupFilterLinks( not_null container, not_null window, diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.h b/Telegram/SourceFiles/boxes/filters/edit_filter_links.h index a2024faa4..dca57121a 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.h +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.h @@ -36,10 +36,11 @@ void ExportFilterLink( Fn done, Fn fail); -object_ptr ShowLinkBox( +[[nodiscard]] object_ptr ShowLinkBox( not_null window, const Data::ChatFilter &filter, const Data::ChatFilterLink &link); +[[nodiscard]] QString FilterChatStatusText(not_null peer); void SetupFilterLinks( not_null container, diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 18b74ec05..3fc5717d8 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1354,6 +1354,9 @@ void Session::setupChannelLeavingViewer() { history->removeJoinedMessage(); history->updateChatListExistence(); history->updateChatListSortPosition(); + if (!history->inChatList()) { + history->clearFolder(); + } } } }, _lifetime); diff --git a/Telegram/SourceFiles/settings/settings_folders.cpp b/Telegram/SourceFiles/settings/settings_folders.cpp index 0dd60090e..479883322 100644 --- a/Telegram/SourceFiles/settings/settings_folders.cpp +++ b/Telegram/SourceFiles/settings/settings_folders.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_folders.h" #include "apiwrap.h" +#include "api/api_chat_filters.h" // ProcessFilterRemove. #include "boxes/premium_limits_box.h" #include "boxes/filters/edit_filter_box.h" #include "core/application.h" @@ -22,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lottie/lottie_icon.h" #include "main/main_session.h" #include "settings/settings_common.h" +#include "ui/boxes/confirm_box.h" #include "ui/filter_icons.h" #include "ui/layers/generic_box.h" #include "ui/painter.h" @@ -102,6 +104,10 @@ struct FilterRow { not_null button; Data::ChatFilter filter; bool removed = false; + bool removeHasLinks = false; + mtpRequestId removePeersRequestId = 0; + std::vector> suggestRemovePeers; + std::vector> removePeers; bool added = false; bool postponedCountUpdate = false; }; @@ -361,6 +367,81 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { controller->show(Box(FiltersLimitBox, session)); return true; }; + const auto markForRemovalSure = [=](not_null button) { + const auto row = find(button); + if (row->removed || row->removePeersRequestId > 0) { + return; + } else if (row->filter.community() + && !row->filter.always().empty()) { + const auto chosen = crl::guard(button, [=]( + std::vector> peers) { + const auto row = find(button); + row->removePeers = std::move(peers); + row->removed = true; + button->setRemoved(true); + }); + Api::ProcessFilterRemove( + controller, + row->filter.title(), + row->filter.iconEmoji(), + row->filter.always() | ranges::views::transform( + &History::peer + ) | ranges::to_vector, + row->suggestRemovePeers, + chosen); + } else { + row->removePeers = {}; + row->removed = true; + button->setRemoved(true); + } + }; + const auto markForRemoval = [=](not_null button) { + const auto row = find(button); + if (row->removed || row->removePeersRequestId > 0) { + return; + } else if (row->filter.community() && row->removeHasLinks) { + controller->show(Ui::MakeConfirmBox({ + .text = { tr::lng_filters_delete_sure(tr::now) }, + .confirmed = crl::guard(button, [=](Fn close) { + markForRemovalSure(button); + close(); + }), + .confirmText = tr::lng_box_delete(), + .confirmStyle = &st::attentionBoxButton, + })); + } else { + markForRemovalSure(button); + } + }; + const auto remove = [=](not_null button) { + const auto row = find(button); + if (row->removed || row->removePeersRequestId > 0) { + return; + } else if (row->filter.community() && !row->removePeersRequestId) { + row->removePeersRequestId = session->api().request( + MTPcommunities_GetLeaveCommunitySuggestions( + MTP_inputCommunityDialogFilter( + MTP_int(row->filter.id()))) + ).done(crl::guard(button, [=](const MTPVector &result) { + const auto row = find(button); + row->removePeersRequestId = -1; + row->suggestRemovePeers = ranges::views::all( + result.v + ) | ranges::views::transform([=](const MTPPeer &peer) { + return session->data().peer(peerFromMTP(peer)); + }) | ranges::to_vector; + row->removeHasLinks = true; // #TODO filters + markForRemoval(button); + })).fail(crl::guard(button, [=] { + const auto row = find(button); + row->removePeersRequestId = -1; + row->removeHasLinks = false; + markForRemoval(button); + })).send(); + } else { + markForRemoval(button); + } + }; const auto wrap = container->add(object_ptr( container)); const auto addFilter = [=](const Data::ChatFilter &filter) { @@ -368,8 +449,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { object_ptr(wrap, session, filter)); button->removeRequests( ) | rpl::start_with_next([=] { - button->setRemoved(true); - find(button)->removed = true; + remove(button); }, button->lifetime()); button->restoreRequests( ) | rpl::start_with_next([=] { @@ -562,6 +642,7 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { auto updates = std::vector(); auto addRequests = std::vector(); auto removeRequests = std::vector(); + auto removeCommunityRequests = std::vector(); auto &realFilters = session->data().chatsFilters(); const auto &list = realFilters.list(); @@ -590,17 +671,32 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { const auto tl = removed ? MTPDialogFilter() : row.filter.tl(newId); - const auto request = MTPmessages_UpdateDialogFilter( - MTP_flags(removed - ? MTPmessages_UpdateDialogFilter::Flag(0) - : MTPmessages_UpdateDialogFilter::Flag::f_filter), - MTP_int(newId), - tl); - if (removed) { - removeRequests.push_back(request); + const auto removeCommunityWithChats = removed + && row.filter.community() + && !row.removePeers.empty(); + if (removeCommunityWithChats) { + auto inputs = ranges::views::all( + row.removePeers + ) | ranges::views::transform([](not_null peer) { + return MTPInputPeer(peer->input); + }) | ranges::to(); + removeCommunityRequests.push_back( + MTPcommunities_LeaveCommunity( + MTP_inputCommunityDialogFilter(MTP_int(newId)), + MTP_vector(std::move(inputs)))); } else { - addRequests.push_back(request); - order.push_back(newId); + const auto request = MTPmessages_UpdateDialogFilter( + MTP_flags(removed + ? MTPmessages_UpdateDialogFilter::Flag(0) + : MTPmessages_UpdateDialogFilter::Flag::f_filter), + MTP_int(newId), + tl); + if (removed) { + removeRequests.push_back(request); + } else { + addRequests.push_back(request); + order.push_back(newId); + } } updates.push_back(MTP_updateDialogFilter( MTP_flags(removed @@ -629,7 +725,8 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { order = std::move(order), updates = std::move(updates), addRequests = std::move(addRequests), - removeRequests = std::move(removeRequests) + removeRequests = std::move(removeRequests), + removeCommunityRequests = std::move(removeCommunityRequests) ] { const auto api = &session->api(); const auto filters = &session->data().chatsFilters(); @@ -646,18 +743,25 @@ void FilterRowButton::paintEvent(QPaintEvent *e) { filters->apply(update); } auto previousId = mtpRequestId(0); - auto &&requests = ranges::views::concat( - removeRequests, - addRequests); - for (auto &request : requests) { - previousId = api->request( - std::move(request) - ).done([=](const auto &, mtpRequestId id) { - ids->remove(id); - checkFinished(); - }).afterRequest(previousId).send(); - ids->emplace(previousId); - } + const auto sendRequests = [&](const auto &requests) { + for (auto &request : requests) { + previousId = api->request( + std::move(request) + ).done([=](const auto &result, mtpRequestId id) { + if constexpr (std::is_same_v< + std::decay_t, + MTPUpdates>) { + session->api().applyUpdates(result); + } + ids->remove(id); + checkFinished(); + }).afterRequest(previousId).send(); + ids->emplace(previousId); + } + }; + sendRequests(removeRequests); + sendRequests(removeCommunityRequests); + sendRequests(addRequests); if (!order.empty() && !addRequests.empty()) { filters->saveOrder(order, previousId); }