tdesktop/Telegram/SourceFiles/window/window_filters_menu.cpp

198 lines
5.5 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "window/window_filters_menu.h"
#include "mainwindow.h"
#include "window/window_session_controller.h"
#include "window/window_controller.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_chat_filters.h"
#include "boxes/filters/manage_filters_box.h"
#include "lang/lang_keys.h"
#include "ui/filter_icons.h"
#include "styles/style_widgets.h"
#include "styles/style_window.h"
namespace Window {
namespace {
using Icon = Ui::FilterIcon;
[[nodiscard]] Icon ComputeIcon(const Data::ChatFilter &filter) {
using Flag = Data::ChatFilter::Flag;
const auto all = Flag::Contacts
| Flag::NonContacts
| Flag::Groups
| Flag::Channels
| Flag::Bots;
const auto removed = Flag::NoRead | Flag::NoMuted;
const auto people = Flag::Contacts | Flag::NonContacts;
const auto allNoArchive = all | Flag::NoArchived;
if (!filter.always().empty()
|| !filter.never().empty()
|| !(filter.flags() & all)) {
return Icon::Custom;
} else if ((filter.flags() & all) == Flag::Contacts
|| (filter.flags() & all) == Flag::NonContacts
|| (filter.flags() & all) == people) {
return Icon::Private;
} else if ((filter.flags() & all) == Flag::Groups) {
return Icon::Groups;
} else if ((filter.flags() & all) == Flag::Channels) {
return Icon::Channels;
} else if ((filter.flags() & all) == Flag::Bots) {
return Icon::Bots;
} else if ((filter.flags() & removed) == Flag::NoRead) {
return Icon::Unread;
} else if ((filter.flags() & removed) == Flag::NoMuted) {
return Icon::Unmuted;
}
return Icon::Custom;
}
} // namespace
FiltersMenu::FiltersMenu(
not_null<Ui::RpWidget*> parent,
not_null<SessionController*> session)
: _session(session)
, _parent(parent)
, _outer(_parent)
, _menu(&_outer, QString(), st::windowFiltersMainMenu)
, _scroll(&_outer)
, _container(
_scroll.setOwnedWidget(
object_ptr<Ui::VerticalLayout>(&_scroll))) {
setup();
}
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);
}
}, _outer.lifetime());
_parent->heightValue(
) | rpl::start_with_next([=](int height) {
const auto width = st::windowFiltersWidth;
_outer.setGeometry({ 0, 0, width, height });
_menu.resizeToWidth(width);
_menu.move(0, 0);
_scroll.setGeometry(
{ 0, _menu.height(), width, height - _menu.height() });
_container->resizeToWidth(width);
_container->move(0, 0);
}, _outer.lifetime());
const auto filters = &_session->session().data().chatsFilters();
rpl::single(
rpl::empty_value()
) | rpl::then(
filters->changed()
) | rpl::start_with_next([=] {
refresh();
}, _outer.lifetime());
_activeFilterId = _session->activeChatsFilterCurrent();
_session->activeChatsFilter(
) | rpl::filter([=](FilterId id) {
return id != _activeFilterId;
}) | rpl::start_with_next([=](FilterId id) {
const auto i = _filters.find(_activeFilterId);
if (i != end(_filters)) {
i->second->setActive(false);
}
_activeFilterId = id;
const auto j = _filters.find(_activeFilterId);
if (j != end(_filters)) {
j->second->setActive(true);
}
}, _outer.lifetime());
_menu.setClickedCallback([=] {
_session->widget()->showMainMenu();
});
}
void FiltersMenu::refresh() {
const auto filters = &_session->session().data().chatsFilters();
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(),
ComputeIcon(filter),
QString());
}
prepare(-1, tr::lng_filters_setup(tr::now), Icon::Setup, {});
_filters = std::move(now);
}
} // namespace Window