mirror of https://github.com/procxx/kepka.git
Allow reordering filters in side bar.
This commit is contained in:
parent
ba6373a0ae
commit
18805a5ef8
|
@ -32,4 +32,20 @@ void SaveNewFilterPinned(
|
|||
|
||||
}
|
||||
|
||||
void SaveNewOrder(
|
||||
not_null<Main::Session*> session,
|
||||
const std::vector<FilterId> &order) {
|
||||
auto &filters = session->data().chatsFilters();
|
||||
auto ids = QVector<MTPint>();
|
||||
ids.reserve(order.size());
|
||||
for (const auto id : order) {
|
||||
ids.push_back(MTP_int(id));
|
||||
}
|
||||
const auto wrapped = MTP_vector<MTPint>(ids);
|
||||
filters.apply(MTP_updateDialogFilterOrder(wrapped));
|
||||
session->api().request(MTPmessages_UpdateDialogFiltersOrder(
|
||||
wrapped
|
||||
)).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -13,6 +13,12 @@ class Session;
|
|||
|
||||
namespace Api {
|
||||
|
||||
void SaveNewFilterPinned(not_null<Main::Session*> session, FilterId filterId);
|
||||
void SaveNewFilterPinned(
|
||||
not_null<Main::Session*> session,
|
||||
FilterId filterId);
|
||||
|
||||
void SaveNewOrder(
|
||||
not_null<Main::Session*> session,
|
||||
const std::vector<FilterId> &order);
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -16,21 +16,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/filters/manage_filters_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/filter_icons.h"
|
||||
#include "ui/wrap/vertical_layout_reorder.h"
|
||||
#include "api/api_chat_filters.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_window.h"
|
||||
|
||||
namespace Window {
|
||||
namespace {
|
||||
|
||||
using Icon = Ui::FilterIcon;
|
||||
|
||||
} // namespace
|
||||
|
||||
FiltersMenu::FiltersMenu(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<SessionController*> session)
|
||||
: _session(session)
|
||||
, _parent(parent)
|
||||
, _manage(std::make_unique<ManageFiltersPrepare>(_session))
|
||||
, _outer(_parent)
|
||||
, _menu(&_outer, QString(), st::windowFiltersMainMenu)
|
||||
, _scroll(&_outer)
|
||||
|
@ -40,24 +38,17 @@ FiltersMenu::FiltersMenu(
|
|||
setup();
|
||||
}
|
||||
|
||||
FiltersMenu::~FiltersMenu() = default;
|
||||
|
||||
void FiltersMenu::setup() {
|
||||
_outer.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
_outer.show();
|
||||
_outer.paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
const auto bottom = _scroll.y() + _container->height();
|
||||
const auto height = _outer.height() - bottom;
|
||||
if (height <= 0) {
|
||||
return;
|
||||
}
|
||||
const auto fill = clip.intersected(
|
||||
QRect(0, bottom, _outer.width(), height));
|
||||
if (!fill.isEmpty()) {
|
||||
auto p = QPainter(&_outer);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::windowFiltersButton.textBg);
|
||||
p.drawRect(fill);
|
||||
}
|
||||
auto p = QPainter(&_outer);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::windowFiltersButton.textBg);
|
||||
p.drawRect(clip);
|
||||
}, _outer.lifetime());
|
||||
|
||||
_parent->heightValue(
|
||||
|
@ -89,11 +80,15 @@ void FiltersMenu::setup() {
|
|||
const auto i = _filters.find(_activeFilterId);
|
||||
if (i != end(_filters)) {
|
||||
i->second->setActive(false);
|
||||
} else if (!_activeFilterId) {
|
||||
_all->setActive(false);
|
||||
}
|
||||
_activeFilterId = id;
|
||||
const auto j = _filters.find(_activeFilterId);
|
||||
if (j != end(_filters)) {
|
||||
j->second->setActive(true);
|
||||
} else if (!_activeFilterId) {
|
||||
_all->setActive(true);
|
||||
}
|
||||
}, _outer.lifetime());
|
||||
|
||||
|
@ -107,58 +102,125 @@ void FiltersMenu::refresh() {
|
|||
if (filters->list().empty()) {
|
||||
return;
|
||||
}
|
||||
const auto manage = _outer.lifetime().make_state<ManageFiltersPrepare>(
|
||||
_session);
|
||||
auto now = base::flat_map<int, base::unique_qptr<Ui::SideBarButton>>();
|
||||
const auto prepare = [&](
|
||||
FilterId id,
|
||||
const QString &title,
|
||||
Icon icon,
|
||||
const QString &badge) {
|
||||
auto button = base::unique_qptr<Ui::SideBarButton>(_container->add(
|
||||
object_ptr<Ui::SideBarButton>(
|
||||
_container,
|
||||
title,
|
||||
st::windowFiltersButton)));
|
||||
const auto &icons = Ui::LookupFilterIcon(icon);
|
||||
button->setIconOverride(icons.normal, icons.active);
|
||||
if (id > 0) {
|
||||
const auto list = filters->chatsList(id);
|
||||
rpl::single(rpl::empty_value()) | rpl::then(
|
||||
list->unreadStateChanges(
|
||||
) | rpl::map([] { return rpl::empty_value(); })
|
||||
) | rpl::start_with_next([=, raw = button.get()] {
|
||||
const auto &state = list->unreadState();
|
||||
const auto count = (state.chats + state.marks);
|
||||
const auto muted = (state.chatsMuted + state.marksMuted);
|
||||
const auto string = !count
|
||||
? QString()
|
||||
: (count > 99)
|
||||
? "..."
|
||||
: QString::number(count);
|
||||
raw->setBadge(string, count == muted);
|
||||
}, button->lifetime());
|
||||
}
|
||||
button->setActive(_session->activeChatsFilterCurrent() == id);
|
||||
button->setClickedCallback([=] {
|
||||
if (id >= 0) {
|
||||
_session->setActiveChatsFilter(id);
|
||||
} else {
|
||||
manage->showBox();
|
||||
}
|
||||
});
|
||||
now.emplace(id, std::move(button));
|
||||
};
|
||||
prepare(0, tr::lng_filters_all(tr::now), Icon::All, {});
|
||||
for (const auto filter : filters->list()) {
|
||||
prepare(
|
||||
filter.id(),
|
||||
filter.title(),
|
||||
Ui::ComputeFilterIcon(filter),
|
||||
QString());
|
||||
|
||||
if (!_list) {
|
||||
setupList();
|
||||
}
|
||||
_reorder->cancel();
|
||||
auto now = base::flat_map<int, base::unique_qptr<Ui::SideBarButton>>();
|
||||
for (const auto filter : filters->list()) {
|
||||
now.emplace(
|
||||
filter.id(),
|
||||
prepareButton(
|
||||
_list,
|
||||
filter.id(),
|
||||
filter.title(),
|
||||
Ui::ComputeFilterIcon(filter)));
|
||||
}
|
||||
prepare(-1, tr::lng_filters_setup(tr::now), Icon::Setup, {});
|
||||
_filters = std::move(now);
|
||||
_reorder->start();
|
||||
|
||||
_container->resizeToWidth(_outer.width());
|
||||
}
|
||||
|
||||
void FiltersMenu::setupList() {
|
||||
_all = prepareButton(
|
||||
_container,
|
||||
0,
|
||||
tr::lng_filters_all(tr::now),
|
||||
Ui::FilterIcon::All);
|
||||
_list = _container->add(object_ptr<Ui::VerticalLayout>(_container));
|
||||
_setup = prepareButton(
|
||||
_container,
|
||||
-1,
|
||||
tr::lng_filters_setup(tr::now),
|
||||
Ui::FilterIcon::Setup);
|
||||
_reorder = std::make_unique<Ui::VerticalLayoutReorder>(_list);
|
||||
|
||||
_reorder->updates(
|
||||
) | rpl::start_with_next([=](Ui::VerticalLayoutReorder::Single data) {
|
||||
using State = Ui::VerticalLayoutReorder::State;
|
||||
if (data.state == State::Started) {
|
||||
++_reordering;
|
||||
} else {
|
||||
Ui::PostponeCall(&_outer, [=] {
|
||||
--_reordering;
|
||||
});
|
||||
if (data.state == State::Applied) {
|
||||
applyReorder(data.widget, data.oldPosition, data.newPosition);
|
||||
}
|
||||
}
|
||||
}, _outer.lifetime());
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::SideBarButton> FiltersMenu::prepareButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
FilterId id,
|
||||
const QString &title,
|
||||
Ui::FilterIcon icon) {
|
||||
auto button = base::unique_qptr<Ui::SideBarButton>(container->add(
|
||||
object_ptr<Ui::SideBarButton>(
|
||||
container,
|
||||
title,
|
||||
st::windowFiltersButton)));
|
||||
const auto raw = button.get();
|
||||
const auto &icons = Ui::LookupFilterIcon(icon);
|
||||
raw->setIconOverride(icons.normal, icons.active);
|
||||
if (id > 0) {
|
||||
const auto filters = &_session->session().data().chatsFilters();
|
||||
const auto list = filters->chatsList(id);
|
||||
rpl::single(rpl::empty_value()) | rpl::then(
|
||||
list->unreadStateChanges(
|
||||
) | rpl::map([] { return rpl::empty_value(); })
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto &state = list->unreadState();
|
||||
const auto count = (state.chats + state.marks);
|
||||
const auto muted = (state.chatsMuted + state.marksMuted);
|
||||
const auto string = !count
|
||||
? QString()
|
||||
: (count > 99)
|
||||
? "..."
|
||||
: QString::number(count);
|
||||
raw->setBadge(string, count == muted);
|
||||
}, raw->lifetime());
|
||||
}
|
||||
raw->setActive(_session->activeChatsFilterCurrent() == id);
|
||||
raw->setClickedCallback([=] {
|
||||
if (_reordering) {
|
||||
return;
|
||||
} else if (id >= 0) {
|
||||
_session->setActiveChatsFilter(id);
|
||||
} else {
|
||||
_manage->showBox();
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
void FiltersMenu::applyReorder(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
int oldPosition,
|
||||
int newPosition) {
|
||||
if (newPosition == oldPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto filters = &_session->session().data().chatsFilters();
|
||||
const auto &list = filters->list();
|
||||
Assert(oldPosition >= 0 && oldPosition < list.size());
|
||||
Assert(newPosition >= 0 && newPosition < list.size());
|
||||
const auto id = list[oldPosition].id();
|
||||
const auto i = _filters.find(id);
|
||||
Assert(i != end(_filters));
|
||||
Assert(i->second == widget);
|
||||
|
||||
auto order = ranges::view::all(
|
||||
list
|
||||
) | ranges::view::transform(
|
||||
&Data::ChatFilter::id
|
||||
) | ranges::to_vector;
|
||||
base::reorder(order, oldPosition, newPosition);
|
||||
Api::SaveNewOrder(&_session->session(), order);
|
||||
}
|
||||
|
||||
} // namespace Window
|
||||
|
|
|
@ -11,6 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
|
||||
class ManageFiltersPrepare;
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayoutReorder;
|
||||
enum class FilterIcon : uchar;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
|
||||
class SessionController;
|
||||
|
@ -20,19 +27,36 @@ public:
|
|||
FiltersMenu(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<SessionController*> session);
|
||||
~FiltersMenu();
|
||||
|
||||
private:
|
||||
void setup();
|
||||
void refresh();
|
||||
void setupList();
|
||||
void applyReorder(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
int oldPosition,
|
||||
int newPosition);
|
||||
[[nodiscard]] base::unique_qptr<Ui::SideBarButton> prepareButton(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
FilterId id,
|
||||
const QString &title,
|
||||
Ui::FilterIcon icon);
|
||||
|
||||
const not_null<SessionController*> _session;
|
||||
const not_null<Ui::RpWidget*> _parent;
|
||||
std::unique_ptr<ManageFiltersPrepare> _manage;
|
||||
Ui::RpWidget _outer;
|
||||
Ui::SideBarButton _menu;
|
||||
Ui::ScrollArea _scroll;
|
||||
not_null<Ui::VerticalLayout*> _container;
|
||||
Ui::VerticalLayout *_list = nullptr;
|
||||
std::unique_ptr<Ui::VerticalLayoutReorder> _reorder;
|
||||
base::unique_qptr<Ui::SideBarButton> _all;
|
||||
base::unique_qptr<Ui::SideBarButton> _setup;
|
||||
base::flat_map<FilterId, base::unique_qptr<Ui::SideBarButton>> _filters;
|
||||
FilterId _activeFilterId = 0;
|
||||
int _reordering = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 62d4145ba04d8b6205fe0413318bc5a0f19f9410
|
||||
Subproject commit 7de25679dd68f3fb7d2faee77ff5311f4d9587d6
|
|
@ -1 +1 @@
|
|||
Subproject commit ec6744022c1a86f3bead192f9649c10dc424a98b
|
||||
Subproject commit b051948e6947b97394df9f0f8b24e8bf407e596c
|
Loading…
Reference in New Issue