2020-03-03 12:07:22 +00:00
|
|
|
/*
|
|
|
|
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"
|
2020-03-10 12:41:12 +00:00
|
|
|
#include "window/window_controller.h"
|
2020-03-03 12:07:22 +00:00
|
|
|
#include "main/main_session.h"
|
|
|
|
#include "data/data_session.h"
|
|
|
|
#include "data/data_chat_filters.h"
|
2020-03-13 11:07:27 +00:00
|
|
|
#include "boxes/filters/manage_filters_box.h"
|
2020-03-10 12:41:12 +00:00
|
|
|
#include "lang/lang_keys.h"
|
2020-03-03 12:07:22 +00:00
|
|
|
#include "styles/style_widgets.h"
|
|
|
|
#include "styles/style_window.h"
|
|
|
|
|
|
|
|
namespace Window {
|
2020-03-06 13:12:22 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum class Type {
|
|
|
|
Unread,
|
|
|
|
Unmuted,
|
2020-03-10 13:02:23 +00:00
|
|
|
People,
|
|
|
|
Groups,
|
|
|
|
Channels,
|
|
|
|
Bots,
|
2020-03-06 13:12:22 +00:00
|
|
|
Custom,
|
|
|
|
};
|
|
|
|
|
|
|
|
[[nodiscard]] Type ComputeType(const Data::ChatFilter &filter) {
|
|
|
|
using Flag = Data::ChatFilter::Flag;
|
|
|
|
|
|
|
|
const auto all = Flag::Contacts
|
|
|
|
| Flag::NonContacts
|
|
|
|
| Flag::Groups
|
2020-03-13 06:56:03 +00:00
|
|
|
| Flag::Channels
|
2020-03-10 12:41:12 +00:00
|
|
|
| Flag::Bots;
|
2020-03-10 13:02:23 +00:00
|
|
|
const auto removed = Flag::NoRead | Flag::NoMuted;
|
|
|
|
const auto people = Flag::Contacts | Flag::NonContacts;
|
2020-03-13 06:56:03 +00:00
|
|
|
const auto allNoArchive = all | Flag::NoArchived;
|
2020-03-10 13:02:23 +00:00
|
|
|
if (!filter.always().empty()
|
|
|
|
|| !filter.never().empty()
|
|
|
|
|| !(filter.flags() & all)) {
|
2020-03-06 13:12:22 +00:00
|
|
|
return Type::Custom;
|
2020-03-10 13:02:23 +00:00
|
|
|
} else if ((filter.flags() & all) == Flag::Contacts
|
|
|
|
|| (filter.flags() & all) == Flag::NonContacts
|
|
|
|
|| (filter.flags() & all) == people) {
|
|
|
|
return Type::People;
|
|
|
|
} else if ((filter.flags() & all) == Flag::Groups) {
|
|
|
|
return Type::Groups;
|
2020-03-13 06:56:03 +00:00
|
|
|
} else if ((filter.flags() & all) == Flag::Channels) {
|
2020-03-10 13:02:23 +00:00
|
|
|
return Type::Channels;
|
|
|
|
} else if ((filter.flags() & all) == Flag::Bots) {
|
|
|
|
return Type::Bots;
|
|
|
|
} else if ((filter.flags() & removed) == Flag::NoRead) {
|
2020-03-06 13:12:22 +00:00
|
|
|
return Type::Unread;
|
2020-03-10 13:02:23 +00:00
|
|
|
} else if ((filter.flags() & removed) == Flag::NoMuted) {
|
2020-03-06 13:12:22 +00:00
|
|
|
return Type::Unmuted;
|
|
|
|
}
|
|
|
|
return Type::Custom;
|
|
|
|
}
|
|
|
|
|
2020-03-09 09:04:00 +00:00
|
|
|
[[nodiscard]] const style::SideBarButton &ComputeStyle(Type type) {
|
2020-03-06 13:12:22 +00:00
|
|
|
switch (type) {
|
2020-03-09 09:04:00 +00:00
|
|
|
case Type::Unread: return st::windowFiltersUnread;
|
|
|
|
case Type::Unmuted: return st::windowFiltersUnmuted;
|
2020-03-10 13:02:23 +00:00
|
|
|
case Type::People: return st::windowFiltersPrivate;
|
|
|
|
case Type::Groups: return st::windowFiltersGroups;
|
|
|
|
case Type::Channels: return st::windowFiltersChannels;
|
|
|
|
case Type::Bots: return st::windowFiltersBots;
|
2020-03-09 09:04:00 +00:00
|
|
|
case Type::Custom: return st::windowFiltersCustom;
|
2020-03-06 13:12:22 +00:00
|
|
|
}
|
|
|
|
Unexpected("Filter type in FiltersMenu::refresh.");
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
2020-03-03 12:07:22 +00:00
|
|
|
|
2020-03-06 11:37:48 +00:00
|
|
|
FiltersMenu::FiltersMenu(
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<SessionController*> session)
|
2020-03-03 12:07:22 +00:00
|
|
|
: _session(session)
|
2020-03-06 11:37:48 +00:00
|
|
|
, _parent(parent)
|
2020-03-09 09:04:00 +00:00
|
|
|
, _outer(_parent)
|
|
|
|
, _menu(&_outer, QString(), st::windowFiltersMainMenu)
|
|
|
|
, _scroll(&_outer)
|
|
|
|
, _container(
|
|
|
|
_scroll.setOwnedWidget(
|
|
|
|
object_ptr<Ui::VerticalLayout>(&_scroll))) {
|
2020-03-03 12:07:22 +00:00
|
|
|
setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FiltersMenu::setup() {
|
2020-03-09 09:04:00 +00:00
|
|
|
_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::windowFiltersAll.textBg);
|
|
|
|
p.drawRect(fill);
|
|
|
|
}
|
|
|
|
}, _outer.lifetime());
|
|
|
|
|
2020-03-06 11:37:48 +00:00
|
|
|
_parent->heightValue(
|
|
|
|
) | rpl::start_with_next([=](int height) {
|
2020-03-09 09:04:00 +00:00
|
|
|
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());
|
2020-03-03 12:07:22 +00:00
|
|
|
|
|
|
|
const auto filters = &_session->session().data().chatsFilters();
|
|
|
|
rpl::single(
|
|
|
|
rpl::empty_value()
|
|
|
|
) | rpl::then(
|
|
|
|
filters->changed()
|
|
|
|
) | rpl::start_with_next([=] {
|
|
|
|
refresh();
|
2020-03-09 09:04:00 +00:00
|
|
|
}, _outer.lifetime());
|
2020-03-03 12:07:22 +00:00
|
|
|
|
2020-03-09 09:04:00 +00:00
|
|
|
_activeFilterId = _session->activeChatsFilterCurrent();
|
2020-03-03 12:07:22 +00:00
|
|
|
_session->activeChatsFilter(
|
2020-03-09 09:04:00 +00:00
|
|
|
) | 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);
|
2020-03-03 12:07:22 +00:00
|
|
|
}
|
2020-03-09 09:04:00 +00:00
|
|
|
_activeFilterId = id;
|
|
|
|
const auto j = _filters.find(_activeFilterId);
|
|
|
|
if (j != end(_filters)) {
|
|
|
|
j->second->setActive(true);
|
|
|
|
}
|
|
|
|
}, _outer.lifetime());
|
|
|
|
|
|
|
|
_menu.setClickedCallback([=] {
|
|
|
|
_session->widget()->showMainMenu();
|
|
|
|
});
|
2020-03-03 12:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FiltersMenu::refresh() {
|
|
|
|
const auto filters = &_session->session().data().chatsFilters();
|
2020-03-10 12:41:12 +00:00
|
|
|
if (filters->list().empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto manage = _outer.lifetime().make_state<ManageFiltersPrepare>(
|
|
|
|
_session);
|
2020-03-09 09:04:00 +00:00
|
|
|
auto now = base::flat_map<int, base::unique_qptr<Ui::SideBarButton>>();
|
|
|
|
const auto prepare = [&](
|
|
|
|
FilterId id,
|
|
|
|
const QString &title,
|
|
|
|
const style::SideBarButton &st,
|
|
|
|
const QString &badge) {
|
|
|
|
auto button = base::unique_qptr<Ui::SideBarButton>(_container->add(
|
|
|
|
object_ptr<Ui::SideBarButton>(
|
|
|
|
_container,
|
|
|
|
title,
|
|
|
|
st)));
|
2020-03-16 12:12:40 +00:00
|
|
|
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());
|
|
|
|
}
|
2020-03-09 09:04:00 +00:00
|
|
|
button->setActive(_session->activeChatsFilterCurrent() == id);
|
|
|
|
button->setClickedCallback([=] {
|
|
|
|
if (id >= 0) {
|
|
|
|
_session->setActiveChatsFilter(id);
|
|
|
|
} else {
|
2020-03-10 12:41:12 +00:00
|
|
|
manage->showBox();
|
2020-03-09 09:04:00 +00:00
|
|
|
}
|
2020-03-03 12:07:22 +00:00
|
|
|
});
|
2020-03-09 09:04:00 +00:00
|
|
|
now.emplace(id, std::move(button));
|
|
|
|
};
|
2020-03-10 12:41:12 +00:00
|
|
|
prepare(0, tr::lng_filters_all(tr::now), st::windowFiltersAll, {});
|
2020-03-09 09:04:00 +00:00
|
|
|
for (const auto filter : filters->list()) {
|
|
|
|
prepare(
|
|
|
|
filter.id(),
|
|
|
|
filter.title(),
|
|
|
|
ComputeStyle(ComputeType(filter)),
|
|
|
|
QString());
|
2020-03-03 12:07:22 +00:00
|
|
|
}
|
2020-03-10 12:41:12 +00:00
|
|
|
prepare(-1, tr::lng_filters_setup(tr::now), st::windowFiltersSetup, {});
|
2020-03-09 09:04:00 +00:00
|
|
|
_filters = std::move(now);
|
2020-03-03 12:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Window
|