Allow select/deselect all in filter link boxes.

This commit is contained in:
John Preston 2023-04-04 18:37:45 +04:00
parent f05f1f4359
commit 1ffbc122e1
4 changed files with 138 additions and 9 deletions

View file

@ -3598,7 +3598,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_filters_by_link_add_button" = "Add {folder}"; "lng_filters_by_link_add_button" = "Add {folder}";
"lng_filters_by_link_add_no" = "Do not add this folder"; "lng_filters_by_link_add_no" = "Do not add this folder";
"lng_filters_by_link_more" = "Add Chats to Folder"; "lng_filters_by_link_more" = "Add Chats to Folder";
"lng_filters_by_link_more_sure" = "Do you want to join chats and add them to your folder {folder}?"; "lng_filters_by_link_more_sure" = "Do you want to join chats and add them to the folder {folder}?";
"lng_filters_by_link_about" = "You can deselect the chats you don't want to join."; "lng_filters_by_link_about" = "You can deselect the chats you don't want to join.";
"lng_filters_by_link_join_button" = "Join Chats"; "lng_filters_by_link_join_button" = "Join Chats";
"lng_filters_by_link_join_no" = "Do not join any chats"; "lng_filters_by_link_join_no" = "Do not join any chats";

View file

@ -63,6 +63,7 @@ private:
void setupAboveWidget(); void setupAboveWidget();
void setupBelowWidget(); void setupBelowWidget();
void initDesiredHeightValue(); void initDesiredHeightValue();
void toggleAllSelected(bool select);
const not_null<Window::SessionController*> _window; const not_null<Window::SessionController*> _window;
Ui::RpWidget *_addedTopWidget = nullptr; Ui::RpWidget *_addedTopWidget = nullptr;
@ -259,8 +260,6 @@ ToggleChatsController::ToggleChatsController(
} }
void ToggleChatsController::prepare() { void ToggleChatsController::prepare() {
setupAboveWidget();
setupBelowWidget();
auto selected = base::flat_set<not_null<PeerData*>>(); auto selected = base::flat_set<not_null<PeerData*>>();
const auto add = [&](not_null<PeerData*> peer, bool additional = false) { const auto add = [&](not_null<PeerData*> peer, bool additional = false) {
auto row = std::make_unique<PeerListRow>(peer); auto row = std::make_unique<PeerListRow>(peer);
@ -292,6 +291,8 @@ void ToggleChatsController::prepare() {
for (const auto &peer : _additional) { for (const auto &peer : _additional) {
add(peer, true); add(peer, true);
} }
setupAboveWidget();
setupBelowWidget();
initDesiredHeightValue(); initDesiredHeightValue();
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
_selected = std::move(selected); _selected = std::move(selected);
@ -339,7 +340,13 @@ void ToggleChatsController::setupAboveWidget() {
: _chats.empty() : _chats.empty()
? _additional.size() ? _additional.size()
: _chats.size(); : _chats.size();
AddSubsectionTitle( const auto selectableCount = delegate()->peerListFullRowsCount()
- (_action == ToggleAction::Adding ? int(_additional.size()) : 0);
auto selectedCount = _selected.value(
) | rpl::map([](const base::flat_set<not_null<PeerData*>> &selected) {
return int(selected.size());
});
AddFilterSubtitleWithToggles(
realAbove, realAbove,
(_action == ToggleAction::Removing (_action == ToggleAction::Removing
? tr::lng_filters_by_link_quit ? tr::lng_filters_by_link_quit
@ -348,12 +355,41 @@ void ToggleChatsController::setupAboveWidget() {
: tr::lng_filters_by_link_join)( : tr::lng_filters_by_link_join)(
lt_count, lt_count,
rpl::single(float64(count))), rpl::single(float64(count))),
st::filterLinkSubsectionTitlePadding); selectableCount,
std::move(selectedCount),
[=](bool select) { toggleAllSelected(select); });
_aboveHeight = realAbove->heightValue(); _aboveHeight = realAbove->heightValue();
delegate()->peerListSetAboveWidget(std::move(wrap)); delegate()->peerListSetAboveWidget(std::move(wrap));
} }
void ToggleChatsController::toggleAllSelected(bool select) {
auto selected = _selected.current();
if (!select) {
if (selected.empty()) {
return;
}
for (const auto &peer : selected) {
const auto row = delegate()->peerListFindRow(peer->id.value);
Assert(row != nullptr);
delegate()->peerListSetRowChecked(row, false);
}
selected = {};
} else {
const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
const auto row = delegate()->peerListRowAt(i);
const auto peer = row->peer();
if (_action != ToggleAction::Adding ||
!ranges::contains(_additional, peer)) {
delegate()->peerListSetRowChecked(row, true);
selected.emplace(peer);
}
}
}
_selected = std::move(selected);
}
void ToggleChatsController::setupBelowWidget() { void ToggleChatsController::setupBelowWidget() {
if (_chats.empty()) { if (_chats.empty()) {
auto widget = object_ptr<Ui::RpWidget>((QWidget*)nullptr); auto widget = object_ptr<Ui::RpWidget>((QWidget*)nullptr);

View file

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/controls/invite_link_label.h" #include "ui/controls/invite_link_label.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/toasts/common_toasts.h" #include "ui/toasts/common_toasts.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -507,6 +508,7 @@ private:
void setupBelowWidget(); void setupBelowWidget();
void addHeader(not_null<Ui::VerticalLayout*> container); void addHeader(not_null<Ui::VerticalLayout*> container);
void addLinkBlock(not_null<Ui::VerticalLayout*> container); void addLinkBlock(not_null<Ui::VerticalLayout*> container);
void toggleAllSelected(bool select);
const not_null<Window::SessionController*> _window; const not_null<Window::SessionController*> _window;
InviteLinkData _data; InviteLinkData _data;
@ -684,8 +686,6 @@ void LinkController::addLinkBlock(not_null<Ui::VerticalLayout*> container) {
void LinkController::prepare() { void LinkController::prepare() {
Expects(!_data.url.isEmpty() || _data.chats.empty()); Expects(!_data.url.isEmpty() || _data.chats.empty());
setupAboveWidget();
setupBelowWidget();
for (const auto &history : _data.chats) { for (const auto &history : _data.chats) {
const auto peer = history->peer; const auto peer = history->peer;
auto row = std::make_unique<ChatRow>( auto row = std::make_unique<ChatRow>(
@ -716,6 +716,8 @@ void LinkController::prepare() {
_denied.emplace(peer); _denied.emplace(peer);
} }
} }
setupAboveWidget();
setupBelowWidget();
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
_selected = _initial; _selected = _initial;
} }
@ -744,6 +746,34 @@ void LinkController::rowClicked(not_null<PeerListRow*> row) {
} }
} }
void LinkController::toggleAllSelected(bool select) {
auto selected = _selected.current();
if (!select) {
if (selected.empty()) {
return;
}
for (const auto &peer : selected) {
const auto row = delegate()->peerListFindRow(peer->id.value);
Assert(row != nullptr);
delegate()->peerListSetRowChecked(row, false);
}
selected = {};
} else {
const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
const auto row = delegate()->peerListRowAt(i);
const auto peer = row->peer();
if (!_denied.contains(peer)) {
delegate()->peerListSetRowChecked(row, true);
selected.emplace(peer);
}
}
}
const auto has = (_initial != selected);
_selected = std::move(selected);
_hasChanges = has;
}
void LinkController::showFinished() { void LinkController::showFinished() {
_showFinished.fire({}); _showFinished.fire({});
} }
@ -770,10 +800,18 @@ void LinkController::setupAboveWidget() {
lt_count, lt_count,
float64(selected.size())); float64(selected.size()));
}); });
Settings::AddSubsectionTitle( const auto mayBeSelected = delegate()->peerListFullRowsCount()
- int(_denied.size());
auto selectedCount = _selected.value(
) | rpl::map([](const base::flat_set<not_null<PeerData*>> &selected) {
return int(selected.size());
});
AddFilterSubtitleWithToggles(
container, container,
std::move(subtitle), std::move(subtitle),
st::filterLinkSubsectionTitlePadding); mayBeSelected,
std::move(selectedCount),
[=](bool select) { toggleAllSelected(select); });
// Fix label cutting on text change from smaller to longer. // Fix label cutting on text change from smaller to longer.
_selected.changes() | rpl::start_with_next([=] { _selected.changes() | rpl::start_with_next([=] {
@ -1206,3 +1244,51 @@ void SetupFilterLinks(
delegate->setContent(content); delegate->setContent(content);
controller->setDelegate(delegate); controller->setDelegate(delegate);
} }
void AddFilterSubtitleWithToggles(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,
int selectableCount,
rpl::producer<int> selectedCount,
Fn<void(bool select)> toggle) {
using namespace rpl::mappers;
const auto selectable = (selectableCount > 0);
auto padding = st::filterLinkSubsectionTitlePadding;
if (selectable) {
const auto font = st::boxLinkButton.font;
padding.setRight(padding.right() + font->spacew + std::max(
font->width(tr::lng_filters_by_link_select(tr::now)),
font->width(tr::lng_filters_by_link_deselect(tr::now))));
}
const auto title = Settings::AddSubsectionTitle(
container,
std::move(text),
padding);
if (!selectable) {
return;
}
const auto link = Ui::CreateChild<Ui::LinkButton>(
container.get(),
tr::lng_filters_by_link_select(tr::now),
st::boxLinkButton);
const auto canSelect = link->lifetime().make_state<rpl::variable<bool>>(
std::move(selectedCount) | rpl::map(_1 < selectableCount));
canSelect->value(
) | rpl::start_with_next([=](bool can) {
link->setText(can
? tr::lng_filters_by_link_select(tr::now)
: tr::lng_filters_by_link_deselect(tr::now));
}, link->lifetime());
link->setClickedCallback([=] {
toggle(canSelect->current());
});
rpl::combine(
container->widthValue(),
title->topValue(),
link->widthValue()
) | rpl::start_with_next([=](int outer, int y, int width) {
link->move(outer - st::boxRowPadding.right() - width, y);
}, link->lifetime());
}

View file

@ -47,3 +47,10 @@ void SetupFilterLinks(
not_null<Window::SessionController*> window, not_null<Window::SessionController*> window,
rpl::producer<std::vector<Data::ChatFilterLink>> value, rpl::producer<std::vector<Data::ChatFilterLink>> value,
Fn<Data::ChatFilter()> currentFilter); Fn<Data::ChatFilter()> currentFilter);
void AddFilterSubtitleWithToggles(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,
int selectableCount,
rpl::producer<int> selectedCount,
Fn<void(bool select)> toggle);