/* 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 parent, not_null session) : _session(session) , _parent(parent) , _outer(_parent) , _menu(&_outer, QString(), st::windowFiltersMainMenu) , _scroll(&_outer) , _container( _scroll.setOwnedWidget( object_ptr(&_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( _session); auto now = base::flat_map>(); const auto prepare = [&]( FilterId id, const QString &title, Icon icon, const QString &badge) { auto button = base::unique_qptr(_container->add( object_ptr( _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