From 71f7aae948661e57d7969a81a781c4f5f1191da5 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Fri, 7 Feb 2020 13:43:12 +0400
Subject: [PATCH] Replace dialogs mode with filters.

---
 Telegram/CMakeLists.txt                       |   2 +
 Telegram/SourceFiles/boxes/share_box.cpp      |   5 +-
 Telegram/SourceFiles/core/application.cpp     |   4 +-
 .../SourceFiles/data/data_chat_filters.cpp    |  53 +++++++++
 Telegram/SourceFiles/data/data_chat_filters.h |  45 ++++++++
 Telegram/SourceFiles/data/data_folder.cpp     |   4 -
 Telegram/SourceFiles/data/data_folder.h       |   1 -
 Telegram/SourceFiles/data/data_session.cpp    |  40 +++----
 Telegram/SourceFiles/data/data_types.h        |   1 +
 .../SourceFiles/dialogs/dialogs_entry.cpp     | 105 +++++++++---------
 Telegram/SourceFiles/dialogs/dialogs_entry.h  |  43 ++++---
 .../dialogs/dialogs_indexed_list.cpp          |  46 ++++----
 .../dialogs/dialogs_indexed_list.h            |   6 +-
 .../dialogs/dialogs_inner_widget.cpp          |  88 ++++++++-------
 .../dialogs/dialogs_inner_widget.h            |   5 +-
 .../SourceFiles/dialogs/dialogs_main_list.cpp |  26 +++--
 .../SourceFiles/dialogs/dialogs_main_list.h   |   8 +-
 .../SourceFiles/dialogs/dialogs_widget.cpp    |   4 +-
 Telegram/SourceFiles/dialogs/dialogs_widget.h |   3 +-
 Telegram/SourceFiles/facades.cpp              |   8 +-
 Telegram/SourceFiles/facades.h                |   8 +-
 Telegram/SourceFiles/history/history.cpp      |  31 +++---
 Telegram/SourceFiles/history/history.h        |   1 -
 Telegram/SourceFiles/mainwidget.cpp           |   4 +-
 Telegram/SourceFiles/mainwidget.h             |   3 +-
 .../SourceFiles/settings/settings_codes.cpp   |   2 +-
 Telegram/SourceFiles/storage/localstorage.cpp |  18 +--
 .../window/window_session_controller.cpp      |   2 +-
 28 files changed, 330 insertions(+), 236 deletions(-)
 create mode 100644 Telegram/SourceFiles/data/data_chat_filters.cpp
 create mode 100644 Telegram/SourceFiles/data/data_chat_filters.h

diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index b7be40f6b..cb7a45ef9 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -320,6 +320,8 @@ PRIVATE
     data/data_auto_download.h
     data/data_chat.cpp
     data/data_chat.h
+    data/data_chat_filters.cpp
+    data/data_chat_filters.h
     data/data_channel.cpp
     data/data_channel.h
     data/data_channel_admins.cpp
diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp
index 9719bee0b..09bb042f0 100644
--- a/Telegram/SourceFiles/boxes/share_box.cpp
+++ b/Telegram/SourceFiles/boxes/share_box.cpp
@@ -937,10 +937,7 @@ void ShareBox::Inner::changeCheckState(Chat *chat) {
 		const auto history = chat->peer->owner().history(chat->peer);
 		auto row = _chatsIndexed->getRow(history);
 		if (!row) {
-			const auto rowsByLetter = _chatsIndexed->addToEnd(history);
-			const auto it = rowsByLetter.find(0);
-			Assert(it != rowsByLetter.cend());
-			row = it->second;
+			row = _chatsIndexed->addToEnd(history).main;
 		}
 		chat = getChat(row);
 		if (!chat->checkbox.checked()) {
diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp
index f3bbacb66..18f3bf4f2 100644
--- a/Telegram/SourceFiles/core/application.cpp
+++ b/Telegram/SourceFiles/core/application.cpp
@@ -503,8 +503,8 @@ void Application::switchDebugMode() {
 }
 
 void Application::switchWorkMode() {
-	Global::SetDialogsModeEnabled(!Global::DialogsModeEnabled());
-	Global::SetDialogsMode(Dialogs::Mode::All);
+	Global::SetDialogsFiltersEnabled(!Global::DialogsFiltersEnabled());
+	Global::SetDialogsFilterId(0);
 	Local::writeUserSettings();
 	App::restart();
 }
diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp
new file mode 100644
index 000000000..b71d77cbb
--- /dev/null
+++ b/Telegram/SourceFiles/data/data_chat_filters.cpp
@@ -0,0 +1,53 @@
+/*
+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 "data/data_chat_filters.h"
+
+#include "history/history.h"
+#include "data/data_peer.h"
+#include "data/data_user.h"
+#include "data/data_chat.h"
+#include "data/data_channel.h"
+
+namespace Data {
+
+ChatFilter::ChatFilter(
+	const QString &title,
+	Flags flags,
+	base::flat_set<not_null<History*>> always)
+: _title(title)
+, _always(std::move(always))
+, _flags(flags) {
+}
+
+bool ChatFilter::contains(not_null<History*> history) const {
+	const auto flag = [&] {
+		const auto peer = history->peer;
+		if (const auto user = peer->asUser()) {
+			return user->isBot() ? Flag::Bots : Flag::Users;
+		} else if (const auto chat = peer->asChat()) {
+			return Flag::PrivateGroups;
+		} else if (const auto channel = peer->asChannel()) {
+			if (channel->isBroadcast()) {
+				return Flag::Broadcasts;
+			} else if (channel->isPublic()) {
+				return Flag::PublicGroups;
+			} else {
+				return Flag::PrivateGroups;
+			}
+		} else {
+			Unexpected("Peer type in ChatFilter::contains.");
+		}
+	}();
+	return false
+		|| ((_flags & flag)
+			&& (!(_flags & Flag::NoMuted) || !history->mute())
+			&& (!(_flags & Flag::NoRead) || history->unreadCountForBadge()))
+		|| _always.contains(history);
+}
+
+} // namespace Data
diff --git a/Telegram/SourceFiles/data/data_chat_filters.h b/Telegram/SourceFiles/data/data_chat_filters.h
new file mode 100644
index 000000000..bc12246a0
--- /dev/null
+++ b/Telegram/SourceFiles/data/data_chat_filters.h
@@ -0,0 +1,45 @@
+/*
+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
+*/
+#pragma once
+
+#include "base/flags.h"
+
+class History;
+
+namespace Data {
+
+class ChatFilter final {
+public:
+	enum class Flag : uchar {
+		Users         = 0x01,
+		PrivateGroups = 0x02,
+		PublicGroups  = 0x04,
+		Broadcasts    = 0x08,
+		Bots          = 0x10,
+		NoMuted       = 0x20,
+		NoRead        = 0x40,
+	};
+	friend constexpr inline bool is_flag_type(Flag) { return true; };
+	using Flags = base::flags<Flag>;
+
+	ChatFilter() = default;
+	ChatFilter(
+		const QString &title,
+		Flags flags,
+		base::flat_set<not_null<History*>> always);
+
+	[[nodiscard]] bool contains(not_null<History*> history) const;
+
+private:
+	QString _title;
+	base::flat_set<not_null<History*>> _always;
+	Flags _flags;
+
+};
+
+} // namespace Data
diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp
index 5229de94b..df513684b 100644
--- a/Telegram/SourceFiles/data/data_folder.cpp
+++ b/Telegram/SourceFiles/data/data_folder.cpp
@@ -441,10 +441,6 @@ void Folder::unreadEntryChanged(
 //	return _unreadPosition.changes();
 //}
 
-bool Folder::toImportant() const {
-	return false;
-}
-
 int Folder::fixedOnTopIndex() const {
 	return kArchiveFixOnTopIndex;
 }
diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h
index 26a9b8d58..f1898f522 100644
--- a/Telegram/SourceFiles/data/data_folder.h
+++ b/Telegram/SourceFiles/data/data_folder.h
@@ -58,7 +58,6 @@ public:
 	TimeId adjustedChatListTimeId() const override;
 
 	int fixedOnTopIndex() const override;
-	bool toImportant() const override;
 	bool shouldBeInChatList() const override;
 	int chatListUnreadCount() const override;
 	bool chatListUnreadMark() const override;
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 7fa9f0a06..3479bf6c6 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -3363,25 +3363,25 @@ auto Session::refreshChatListEntry(Dialogs::Key key)
 	auto result = RefreshChatListEntryResult();
 	result.changed = !entry->inChatList();
 	if (result.changed) {
-		const auto mainRow = entry->addToChatList(Mode::All);
+		const auto mainRow = entry->addToChatList(0);
 		_contactsNoChatsList.del(key, mainRow);
 	} else {
-		result.moved = entry->adjustByPosInChatList(Mode::All);
-	}
-	if (Global::DialogsModeEnabled()) {
-		if (entry->toImportant()) {
-			result.importantChanged = !entry->inChatList(Mode::Important);
-			if (result.importantChanged) {
-				entry->addToChatList(Mode::Important);
-			} else {
-				result.importantMoved = entry->adjustByPosInChatList(
-					Mode::Important);
-			}
-		} else if (entry->inChatList(Mode::Important)) {
-			entry->removeFromChatList(Mode::Important);
-			result.importantChanged = true;
-		}
+		result.moved = entry->adjustByPosInChatList(0);
 	}
+	//if (Global::DialogsFiltersEnabled()) { // #TODO filters
+	//	if (entry->toImportant()) {
+	//		result.importantChanged = !entry->inChatList(Mode::Important);
+	//		if (result.importantChanged) {
+	//			entry->addToChatList(Mode::Important);
+	//		} else {
+	//			result.importantMoved = entry->adjustByPosInChatList(
+	//				Mode::Important);
+	//		}
+	//	} else if (entry->inChatList(Mode::Important)) {
+	//		entry->removeFromChatList(Mode::Important);
+	//		result.importantChanged = true;
+	//	}
+	//}
 	return result;
 }
 
@@ -3389,10 +3389,10 @@ void Session::removeChatListEntry(Dialogs::Key key) {
 	using namespace Dialogs;
 
 	const auto entry = key.entry();
-	entry->removeFromChatList(Mode::All);
-	if (Global::DialogsModeEnabled()) {
-		entry->removeFromChatList(Mode::Important);
-	}
+	entry->removeFromChatList(0);
+	//if (Global::DialogsFiltersEnabled()) { // #TODO filters
+	//	entry->removeFromChatList(Mode::Important);
+	//}
 	if (_contactsList.contains(key)) {
 		if (!_contactsNoChatsList.contains(key)) {
 			_contactsNoChatsList.addByName(key);
diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h
index 2b452b3e4..66d95966b 100644
--- a/Telegram/SourceFiles/data/data_types.h
+++ b/Telegram/SourceFiles/data/data_types.h
@@ -128,6 +128,7 @@ using UserId = int32;
 using ChatId = int32;
 using ChannelId = int32;
 using FolderId = int32;
+using FilterId = int32;
 
 constexpr auto NoChannel = ChannelId(0);
 
diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
index d56ae68d9..4db2f9ff2 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp
@@ -131,25 +131,33 @@ TimeId Entry::adjustedChatListTimeId() const {
 void Entry::changedChatListPinHook() {
 }
 
-RowsByLetter &Entry::chatListLinks(Mode list) {
-	return _chatListLinks[static_cast<int>(list)];
+RowsByLetter *Entry::chatListLinks(FilterId filterId) {
+	const auto i = _chatListLinks.find(filterId);
+	return (i != end(_chatListLinks)) ? &i->second : nullptr;
 }
 
-const RowsByLetter &Entry::chatListLinks(Mode list) const {
-	return _chatListLinks[static_cast<int>(list)];
+const RowsByLetter *Entry::chatListLinks(FilterId filterId) const {
+	const auto i = _chatListLinks.find(filterId);
+	return (i != end(_chatListLinks)) ? &i->second : nullptr;
 }
 
-Row *Entry::mainChatListLink(Mode list) const {
-	auto it = chatListLinks(list).find(0);
-	Assert(it != chatListLinks(list).cend());
-	return it->second;
+not_null<Row*> Entry::mainChatListLink(FilterId filterId) const {
+	const auto links = chatListLinks(filterId);
+	Assert(links != nullptr);
+	return links->main;
 }
 
-PositionChange Entry::adjustByPosInChatList(Mode list) {
-	const auto lnk = mainChatListLink(list);
-	const auto from = lnk->pos();
-	myChatsList(list)->adjustByDate(chatListLinks(list));
-	const auto to = lnk->pos();
+Row *Entry::maybeMainChatListLink(FilterId filterId) const {
+	const auto links = chatListLinks(filterId);
+	return links ? links->main.get() : nullptr;
+}
+
+PositionChange Entry::adjustByPosInChatList(FilterId filterId) {
+	const auto links = chatListLinks(filterId);
+	Assert(links != nullptr);
+	const auto from = links->main->pos();
+	myChatsList(filterId)->adjustByDate(*links);
+	const auto to = links->main->pos();
 	return { from, to };
 }
 
@@ -161,60 +169,57 @@ void Entry::setChatListTimeId(TimeId date) {
 	}
 }
 
-int Entry::posInChatList(Dialogs::Mode list) const {
-	return mainChatListLink(list)->pos();
+int Entry::posInChatList(FilterId filterId) const {
+	return mainChatListLink(filterId)->pos();
 }
 
-not_null<Row*> Entry::addToChatList(Mode list) {
-	if (!inChatList(list)) {
-		chatListLinks(list) = myChatsList(list)->addToEnd(_key);
-		if (list == Mode::All) {
-			owner().unreadEntryChanged(_key, true);
-		}
+not_null<Row*> Entry::addToChatList(FilterId filterId) {
+	if (const auto main = maybeMainChatListLink(filterId)) {
+		return main;
 	}
-	return mainChatListLink(list);
+	const auto result = _chatListLinks.emplace(
+		filterId,
+		myChatsList(filterId)->addToEnd(_key)
+	).first->second.main;
+	if (!filterId) {
+		owner().unreadEntryChanged(_key, true);
+	}
+	return result;
 }
 
-void Entry::removeFromChatList(Dialogs::Mode list) {
-	if (inChatList(list)) {
-		myChatsList(list)->del(_key);
-		chatListLinks(list).clear();
-		if (list == Mode::All) {
-			owner().unreadEntryChanged(_key, false);
-		}
+void Entry::removeFromChatList(FilterId filterId) {
+	const auto i = _chatListLinks.find(filterId);
+	if (i == end(_chatListLinks)) {
+		return;
+	}
+	myChatsList(filterId)->del(_key);
+	_chatListLinks.erase(i);
+	if (!filterId) {
+		owner().unreadEntryChanged(_key, false);
 	}
 }
 
-void Entry::removeChatListEntryByLetter(Mode list, QChar letter) {
-	Expects(letter != 0);
-
-	if (inChatList(list)) {
-		chatListLinks(list).remove(letter);
+void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) {
+	const auto i = _chatListLinks.find(filterId);
+	if (i != end(_chatListLinks)) {
+		i->second.letters.remove(letter);
 	}
 }
 
 void Entry::addChatListEntryByLetter(
-		Mode list,
+		FilterId filterId,
 		QChar letter,
 		not_null<Row*> row) {
-	Expects(letter != 0);
-
-	if (inChatList(list)) {
-		chatListLinks(list).emplace(letter, row);
+	const auto i = _chatListLinks.find(filterId);
+	if (i != end(_chatListLinks)) {
+		i->second.letters.emplace(letter, row);
 	}
 }
 
 void Entry::updateChatListEntry() const {
 	if (const auto main = App::main()) {
-		if (inChatList()) {
-			main->repaintDialogRow(
-				Mode::All,
-				mainChatListLink(Mode::All));
-			if (inChatList(Mode::Important)) {
-				main->repaintDialogRow(
-					Mode::Important,
-					mainChatListLink(Mode::Important));
-			}
+		for (const auto &[filterId, links] : _chatListLinks) {
+			main->repaintDialogRow(filterId, links.main);
 		}
 		if (session().supportMode()
 			&& !session().settings().supportAllSearchResults()) {
@@ -223,8 +228,8 @@ void Entry::updateChatListEntry() const {
 	}
 }
 
-not_null<IndexedList*> Entry::myChatsList(Mode list) const {
-	return owner().chatsList(folder())->indexed(list);
+not_null<IndexedList*> Entry::myChatsList(FilterId filterId) const {
+	return owner().chatsList(folder())->indexed(filterId);
 }
 
 } // namespace Dialogs
diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h
index ed0ec0191..0f8945693 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_entry.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h
@@ -24,7 +24,11 @@ namespace Dialogs {
 
 class Row;
 class IndexedList;
-using RowsByLetter = base::flat_map<QChar, not_null<Row*>>;
+
+struct RowsByLetter {
+	not_null<Row*> main;
+	base::flat_map<QChar, not_null<Row*>> letters;
+};
 
 enum class SortMode {
 	Date = 0x00,
@@ -32,11 +36,6 @@ enum class SortMode {
 	Add  = 0x02,
 };
 
-enum class Mode {
-	All       = 0x00,
-	Important = 0x01,
-};
-
 struct PositionChange {
 	int from = -1;
 	int to = -1;
@@ -94,19 +93,19 @@ public:
 	Entry &operator=(const Entry &other) = delete;
 	virtual ~Entry() = default;
 
-	Data::Session &owner() const;
-	Main::Session &session() const;
+	[[nodiscard]] Data::Session &owner() const;
+	[[nodiscard]] Main::Session &session() const;
 
-	PositionChange adjustByPosInChatList(Mode list);
-	bool inChatList(Mode list = Mode::All) const {
-		return !chatListLinks(list).empty();
+	PositionChange adjustByPosInChatList(FilterId filterId);
+	[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
+		return _chatListLinks.contains(filterId);
 	}
-	int posInChatList(Mode list) const;
-	not_null<Row*> addToChatList(Mode list);
-	void removeFromChatList(Mode list);
-	void removeChatListEntryByLetter(Mode list, QChar letter);
+	[[nodiscard]] int posInChatList(FilterId filterId) const;
+	not_null<Row*> addToChatList(FilterId filterId);
+	void removeFromChatList(FilterId filterId);
+	void removeChatListEntryByLetter(FilterId filterId, QChar letter);
 	void addChatListEntryByLetter(
-		Mode list,
+		FilterId filterId,
 		QChar letter,
 		not_null<Row*> row);
 	void updateChatListEntry() const;
@@ -131,7 +130,6 @@ public:
 	static constexpr auto kArchiveFixOnTopIndex = 1;
 	static constexpr auto kProxyPromotionFixOnTopIndex = 2;
 
-	virtual bool toImportant() const = 0;
 	virtual bool shouldBeInChatList() const = 0;
 	virtual int chatListUnreadCount() const = 0;
 	virtual bool chatListUnreadMark() const = 0;
@@ -190,15 +188,16 @@ private:
 	void notifyUnreadStateChange(const UnreadState &wasState);
 
 	void setChatListExistence(bool exists);
-	RowsByLetter &chatListLinks(Mode list);
-	const RowsByLetter &chatListLinks(Mode list) const;
-	Row *mainChatListLink(Mode list) const;
+	RowsByLetter *chatListLinks(FilterId filterId);
+	const RowsByLetter *chatListLinks(FilterId filterId) const;
+	not_null<Row*> mainChatListLink(FilterId filterId) const;
+	Row *maybeMainChatListLink(FilterId filterId) const;
 
-	not_null<IndexedList*> myChatsList(Mode list) const;
+	not_null<IndexedList*> myChatsList(FilterId filterId) const;
 
 	not_null<Data::Session*> _owner;
 	Dialogs::Key _key;
-	RowsByLetter _chatListLinks[2];
+	base::flat_map<FilterId, RowsByLetter> _chatListLinks;
 	uint64 _sortKeyInChatList = 0;
 	int _pinnedIndex = 0;
 	bool _isProxyPromoted = false;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp
index b5bb69044..2ee60cebb 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp
@@ -20,16 +20,17 @@ IndexedList::IndexedList(SortMode sortMode)
 }
 
 RowsByLetter IndexedList::addToEnd(Key key) {
-	RowsByLetter result;
-	if (!_list.contains(key)) {
-		result.emplace(0, _list.addToEnd(key));
-		for (const auto ch : key.entry()->chatListFirstLetters()) {
-			auto j = _index.find(ch);
-			if (j == _index.cend()) {
-				j = _index.emplace(ch, _sortMode).first;
-			}
-			result.emplace(ch, j->second.addToEnd(key));
+	if (const auto row = _list.getRow(key)) {
+		return { row };
+	}
+
+	auto result = RowsByLetter{ _list.addToEnd(key) };
+	for (const auto ch : key.entry()->chatListFirstLetters()) {
+		auto j = _index.find(ch);
+		if (j == _index.cend()) {
+			j = _index.emplace(ch, _sortMode).first;
 		}
+		result.letters.emplace(ch, j->second.addToEnd(key));
 	}
 	return result;
 }
@@ -51,13 +52,10 @@ Row *IndexedList::addByName(Key key) {
 }
 
 void IndexedList::adjustByDate(const RowsByLetter &links) {
-	for (const auto [ch, row] : links) {
-		if (ch == QChar(0)) {
-			_list.adjustByDate(row);
-		} else {
-			if (auto it = _index.find(ch); it != _index.cend()) {
-				it->second.adjustByDate(row);
-			}
+	_list.adjustByDate(links.main);
+	for (const auto [ch, row] : links.letters) {
+		if (auto it = _index.find(ch); it != _index.cend()) {
+			it->second.adjustByDate(row);
 		}
 	}
 }
@@ -95,19 +93,19 @@ void IndexedList::peerNameChanged(
 		if (_sortMode == SortMode::Name) {
 			adjustByName(history, oldLetters);
 		} else {
-			adjustNames(Dialogs::Mode::All, history, oldLetters);
+			adjustNames(FilterId(), history, oldLetters);
 		}
 	}
 }
 
 void IndexedList::peerNameChanged(
-		Mode list,
+		FilterId filterId,
 		not_null<PeerData*> peer,
 		const base::flat_set<QChar> &oldLetters) {
 	Expects(_sortMode == SortMode::Date);
 
 	if (const auto history = peer->owner().historyLoaded(peer)) {
-		adjustNames(list, history, oldLetters);
+		adjustNames(filterId, history, oldLetters);
 	}
 }
 
@@ -149,7 +147,7 @@ void IndexedList::adjustByName(
 }
 
 void IndexedList::adjustNames(
-		Mode list,
+		FilterId filterId,
 		not_null<History*> history,
 		const base::flat_set<QChar> &oldLetters) {
 	const auto key = Dialogs::Key(history);
@@ -168,7 +166,7 @@ void IndexedList::adjustNames(
 	}
 	for (auto ch : toRemove) {
 		if (_sortMode == SortMode::Date) {
-			history->removeChatListEntryByLetter(list, ch);
+			history->removeChatListEntryByLetter(filterId, ch);
 		}
 		if (auto it = _index.find(ch); it != _index.cend()) {
 			it->second.del(key, mainRow);
@@ -181,7 +179,7 @@ void IndexedList::adjustNames(
 		}
 		auto row = j->second.addToEnd(key);
 		if (_sortMode == SortMode::Date) {
-			history->addChatListEntryByLetter(list, ch, row);
+			history->addChatListEntryByLetter(filterId, ch, row);
 		}
 	}
 }
@@ -250,8 +248,4 @@ std::vector<not_null<Row*>> IndexedList::filtered(
 	return result;
 }
 
-IndexedList::~IndexedList() {
-	clear();
-}
-
 } // namespace Dialogs
diff --git a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h
index 05b4fb987..65bb30d89 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h
@@ -33,7 +33,7 @@ public:
 
 	//For sortMode == SortMode::Date
 	void peerNameChanged(
-		Mode list,
+		FilterId filterId,
 		not_null<PeerData*> peer,
 		const base::flat_set<QChar> &oldChars);
 
@@ -49,8 +49,6 @@ public:
 	}
 	std::vector<not_null<Row*>> filtered(const QStringList &words) const;
 
-	~IndexedList();
-
 	// Part of List interface is duplicated here for all() list.
 	int size() const { return all().size(); }
 	bool empty() const { return all().empty(); }
@@ -78,7 +76,7 @@ private:
 		Key key,
 		const base::flat_set<QChar> &oldChars);
 	void adjustNames(
-		Mode list,
+		FilterId filterId,
 		not_null<History*> history,
 		const base::flat_set<QChar> &oldChars);
 
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
index 5af51519d..f8b47ffd5 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp
@@ -118,9 +118,9 @@ InnerWidget::InnerWidget(
 	setAttribute(Qt::WA_OpaquePaintEvent, true);
 #endif // OS_MAC_OLD
 
-	_mode = Global::DialogsModeEnabled()
-		? Global::DialogsMode()
-		: Dialogs::Mode::All;
+	_filterId = Global::DialogsFiltersEnabled()
+		? Global::DialogsFilterId()
+		: 0;
 
 	_addContactLnk->addClickHandler([] { App::wnd()->onShowAddContact(); });
 	_cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); });
@@ -280,7 +280,7 @@ void InnerWidget::refreshWithCollapsedRows(bool toTop) {
 	_collapsedSelected = -1;
 
 	_collapsedRows.clear();
-	if (!_openedFolder && Global::DialogsModeEnabled()) {
+	if (!_openedFolder && Global::DialogsFiltersEnabled()) {
 		_collapsedRows.push_back(std::make_unique<CollapsedRow>());
 	}
 	const auto list = shownDialogs();
@@ -368,7 +368,7 @@ void InnerWidget::changeOpenedFolder(Data::Folder *folder) {
 	//const auto lastMousePosition = _lastMousePosition;
 	clearSelection();
 	_openedFolder = folder;
-	_mode = _openedFolder ? Mode::All : Global::DialogsMode();
+	_filterId = _openedFolder ? 0 : Global::DialogsFilterId();
 	refreshWithCollapsedRows(true);
 	// This doesn't work, because we clear selection in leaveEvent on hide.
 	//if (mouseSelection && lastMousePosition) {
@@ -686,12 +686,12 @@ void InnerWidget::paintCollapsedRow(
 	const auto narrow = (width() <= smallWidth);
 	const auto text = row->folder
 		? row->folder->chatListName()
-		: (_mode == Dialogs::Mode::Important)
+		: _filterId // #TODO filters
 		? (narrow ? "Show" : tr::lng_dialogs_show_all_chats(tr::now))
 		: (narrow ? "Hide" : tr::lng_dialogs_hide_muted_chats(tr::now));
 	const auto unread = row->folder
 		? row->folder->chatListUnreadCount()
-		: (_mode == Dialogs::Mode::Important)
+		: _filterId // #TODO filters
 		? session().data().unreadOnlyMutedBadge()
 		: 0;
 	Layout::PaintCollapsedRow(
@@ -1049,11 +1049,11 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
 		});
 	} else if (base::in_range(_filteredPressed, 0, _filterResults.size())) {
 		const auto row = _filterResults[_filteredPressed];
-		const auto list = _mode;
+		const auto filterId = _filterId;
 		row->addRipple(
 			e->pos() - QPoint(0, filteredOffset() + _filteredPressed * st::dialogsRowHeight),
 			QSize(width(), st::dialogsRowHeight),
-			[=] { repaintDialogRow(list, row); });
+			[=] { repaintDialogRow(filterId, row); });
 	} else if (base::in_range(_peerSearchPressed, 0, _peerSearchResults.size())) {
 		auto &result = _peerSearchResults[_peerSearchPressed];
 		auto row = &result->row;
@@ -1435,10 +1435,10 @@ void InnerWidget::refreshDialog(Key key) {
 	}
 
 	const auto result = session().data().refreshChatListEntry(key);
-	const auto changed = (_mode == Mode::Important)
+	const auto changed = _filterId // #TODO filters
 		? result.importantChanged
 		: result.changed;
-	const auto moved = (_mode == Mode::Important)
+	const auto moved = _filterId // #TODO filters
 		? result.importantMoved
 		: result.moved;
 
@@ -1511,17 +1511,17 @@ int InnerWidget::defaultRowTop(not_null<Row*> row) const {
 }
 
 void InnerWidget::repaintDialogRow(
-		Mode list,
+		FilterId filterId,
 		not_null<Row*> row) {
 	if (_state == WidgetState::Default) {
-		if (_mode == list) {
+		if (_filterId == filterId) {
 			if (const auto folder = row->folder()) {
 				repaintCollapsedFolderRow(folder);
 			}
 			update(0, defaultRowTop(row), width(), st::dialogsRowHeight);
 		}
 	} else if (_state == WidgetState::Filtered) {
-		if (list == Mode::All) {
+		if (!filterId) {
 			for (auto i = 0, l = int(_filterResults.size()); i != l; ++i) {
 				if (_filterResults[i]->key() == row->key()) {
 					update(
@@ -1645,10 +1645,10 @@ void InnerWidget::updateSelectedRow(Key key) {
 	if (_state == WidgetState::Default) {
 		if (key) {
 			const auto entry = key.entry();
-			if (!entry->inChatList(_mode)) {
+			if (!entry->inChatList(_filterId)) {
 				return;
 			}
-			auto position = entry->posInChatList(_mode);
+			auto position = entry->posInChatList(_filterId);
 			auto top = dialogsOffset();
 			if (base::in_range(position, 0, _pinnedRows.size())) {
 				top += qRound(_pinnedRows[position].yadd.current());
@@ -1680,7 +1680,7 @@ void InnerWidget::updateSelectedRow(Key key) {
 }
 
 not_null<IndexedList*> InnerWidget::shownDialogs() const {
-	return session().data().chatsList(_openedFolder)->indexed(_mode);
+	return session().data().chatsList(_openedFolder)->indexed(_filterId);
 }
 
 void InnerWidget::leaveEventHook(QEvent *e) {
@@ -2137,7 +2137,8 @@ void InnerWidget::peerSearchReceived(
 }
 
 void InnerWidget::notify_historyMuteUpdated(History *history) {
-	if (!Global::DialogsModeEnabled() || !history->inChatList()) {
+	// #TODO filters
+	if (!Global::DialogsFiltersEnabled() || !history->inChatList()) {
 		return;
 	}
 	refreshDialog(history);
@@ -2425,22 +2426,23 @@ void InnerWidget::scrollToEntry(const RowDescriptor &entry) {
 
 void InnerWidget::selectSkipPage(int32 pixels, int32 direction) {
 	clearMouseSelection();
+	const auto list = shownDialogs();
 	int toSkip = pixels / int(st::dialogsRowHeight);
 	if (_state == WidgetState::Default) {
 		if (!_selected) {
-			if (direction > 0 && shownDialogs()->size() > _skipTopDialogs) {
-				_selected = *(shownDialogs()->cbegin() + _skipTopDialogs);
+			if (direction > 0 && list->size() > _skipTopDialogs) {
+				_selected = *(list->cbegin() + _skipTopDialogs);
 				_collapsedSelected = -1;
 			} else {
 				return;
 			}
 		}
 		if (direction > 0) {
-			for (auto i = shownDialogs()->cfind(_selected), end = shownDialogs()->cend(); i != end && (toSkip--); ++i) {
+			for (auto i = list->cfind(_selected), end = list->cend(); i != end && (toSkip--); ++i) {
 				_selected = *i;
 			}
 		} else {
-			for (auto i = shownDialogs()->cfind(_selected), b = shownDialogs()->cbegin(); i != b && (*i)->pos() > _skipTopDialogs && (toSkip--);) {
+			for (auto i = list->cfind(_selected), b = list->cbegin(); i != b && (*i)->pos() > _skipTopDialogs && (toSkip--);) {
 				_selected = *(--i);
 			}
 			if (toSkip && !_collapsedRows.empty()) {
@@ -2463,12 +2465,13 @@ void InnerWidget::selectSkipPage(int32 pixels, int32 direction) {
 void InnerWidget::loadPeerPhotos() {
 	if (!parentWidget()) return;
 
+	const auto list = shownDialogs();
 	auto yFrom = _visibleTop;
 	auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
 	if (_state == WidgetState::Default) {
-		auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
+		auto otherStart = list->size() * st::dialogsRowHeight;
 		if (yFrom < otherStart) {
-			for (auto i = shownDialogs()->cfind(yFrom, st::dialogsRowHeight), end = shownDialogs()->cend(); i != end; ++i) {
+			for (auto i = list->cfind(yFrom, st::dialogsRowHeight), end = list->cend(); i != end; ++i) {
 				if (((*i)->pos() * st::dialogsRowHeight) >= yTo) {
 					break;
 				}
@@ -2532,12 +2535,13 @@ bool InnerWidget::chooseCollapsedRow() {
 
 void InnerWidget::switchImportantChats() {
 	clearSelection();
-	if (Global::DialogsMode() == Mode::All) {
-		Global::SetDialogsMode(Mode::Important);
-	} else {
-		Global::SetDialogsMode(Mode::All);
-	}
-	_mode = Global::DialogsMode();
+	// #TODO filters
+	//if (Global::DialogsFilterId() == 0) {
+	//	Global::SetDialogsMode(Mode::Important);
+	//} else {
+	//	Global::SetDialogsMode(Mode::All);
+	//}
+	_filterId = Global::DialogsFilterId();
 	Local::writeUserSettings();
 	refreshWithCollapsedRows(true);
 	_collapsedSelected = 0;
@@ -2633,9 +2637,10 @@ RowDescriptor InnerWidget::chatListEntryBefore(
 		return RowDescriptor();
 	}
 	if (_state == WidgetState::Default) {
-		if (const auto row = shownDialogs()->getRow(which.key)) {
-			const auto i = shownDialogs()->cfind(row);
-			if (i != shownDialogs()->cbegin()) {
+		const auto list = shownDialogs();
+		if (const auto row = list->getRow(which.key)) {
+			const auto i = list->cfind(row);
+			if (i != list->cbegin()) {
 				return RowDescriptor(
 					(*(i - 1))->key(),
 					FullMsgId(NoChannel, ShowAtUnreadMsgId));
@@ -2710,9 +2715,10 @@ RowDescriptor InnerWidget::chatListEntryAfter(
 		return RowDescriptor();
 	}
 	if (_state == WidgetState::Default) {
-		if (const auto row = shownDialogs()->getRow(which.key)) {
-			const auto i = shownDialogs()->cfind(row) + 1;
-			if (i != shownDialogs()->cend()) {
+		const auto list = shownDialogs();
+		if (const auto row = list->getRow(which.key)) {
+			const auto i = list->cfind(row) + 1;
+			if (i != list->cend()) {
 				return RowDescriptor(
 					(*i)->key(),
 					FullMsgId(NoChannel, ShowAtUnreadMsgId));
@@ -2775,8 +2781,9 @@ RowDescriptor InnerWidget::chatListEntryAfter(
 
 RowDescriptor InnerWidget::chatListEntryFirst() const {
 	if (_state == WidgetState::Default) {
-		const auto i = shownDialogs()->cbegin();
-		if (i != shownDialogs()->cend()) {
+		const auto list = shownDialogs();
+		const auto i = list->cbegin();
+		if (i != list->cend()) {
 			return RowDescriptor(
 				(*i)->key(),
 				FullMsgId(NoChannel, ShowAtUnreadMsgId));
@@ -2800,8 +2807,9 @@ RowDescriptor InnerWidget::chatListEntryFirst() const {
 
 RowDescriptor InnerWidget::chatListEntryLast() const {
 	if (_state == WidgetState::Default) {
-		const auto i = shownDialogs()->cend();
-		if (i != shownDialogs()->cbegin()) {
+		const auto list = shownDialogs();
+		const auto i = list->cend();
+		if (i != list->cbegin()) {
 			return RowDescriptor(
 				(*(i - 1))->key(),
 				FullMsgId(NoChannel, ShowAtUnreadMsgId));
diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
index 0015d4501..ddd7ec09c 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h
@@ -38,7 +38,6 @@ namespace Dialogs {
 class Row;
 class FakeRow;
 class IndexedList;
-enum class Mode;
 
 struct ChosenRow {
 	Key key;
@@ -89,7 +88,7 @@ public:
 
 	void refreshDialog(Key key);
 	void removeDialog(Key key);
-	void repaintDialogRow(Mode list, not_null<Row*> row);
+	void repaintDialogRow(FilterId filterId, not_null<Row*> row);
 	void repaintDialogRow(RowDescriptor row);
 
 	void dragLeft();
@@ -310,7 +309,7 @@ private:
 
 	not_null<Window::SessionController*> _controller;
 
-	Mode _mode = Mode();
+	FilterId _filterId = 0;
 	bool _mouseSelection = false;
 	std::optional<QPoint> _lastMousePosition;
 	Qt::MouseButton _pressButton = Qt::LeftButton;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp
index f0827f9b7..c8154578d 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp
@@ -14,7 +14,6 @@ namespace Dialogs {
 
 MainList::MainList(rpl::producer<int> pinnedLimit)
 : _all(SortMode::Date)
-, _important(SortMode::Date)
 , _pinned(1) {
 	_unreadState.known = true;
 
@@ -29,8 +28,10 @@ MainList::MainList(rpl::producer<int> pinnedLimit)
 	) | rpl::start_with_next([=](const Notify::PeerUpdate &update) {
 		const auto peer = update.peer;
 		const auto &oldLetters = update.oldNameFirstLetters;
-		_all.peerNameChanged(Mode::All, peer, oldLetters);
-		_important.peerNameChanged(Mode::Important, peer, oldLetters);
+		_all.peerNameChanged(FilterId(), peer, oldLetters);
+		for (auto &[filterId, list] : _other) {
+			list.peerNameChanged(filterId, peer, oldLetters);
+		}
 	}, _lifetime);
 }
 
@@ -48,7 +49,9 @@ void MainList::setLoaded(bool loaded) {
 
 void MainList::clear() {
 	_all.clear();
-	_important.clear();
+	for (auto &[filterId, list] : _other) { // #TODO filters _other.clear?..
+		list.clear();
+	}
 	_unreadState = UnreadState();
 }
 
@@ -72,12 +75,19 @@ UnreadState MainList::unreadState() const {
 	return _unreadState;
 }
 
-not_null<IndexedList*> MainList::indexed(Mode list) {
-	return (list == Mode::All) ? &_all : &_important;
+not_null<IndexedList*> MainList::indexed(FilterId filterId) {
+	if (!filterId) {
+		return &_all;
+	}
+	const auto i = _other.find(filterId);
+	if (i != end(_other)) {
+		return &i->second;
+	}
+	return &_other.emplace(filterId, SortMode::Date).first->second;
 }
 
-not_null<const IndexedList*> MainList::indexed(Mode list) const {
-	return (list == Mode::All) ? &_all : &_important;
+not_null<const IndexedList*> MainList::indexed() const {
+	return &_all;
 }
 
 not_null<PinnedList*> MainList::pinned() {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.h b/Telegram/SourceFiles/dialogs/dialogs_main_list.h
index ce5831105..4319b836a 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_main_list.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.h
@@ -27,16 +27,16 @@ public:
 	void unreadEntryChanged(
 		const Dialogs::UnreadState &state,
 		bool added);
-	UnreadState unreadState() const;
+	[[nodiscard]] UnreadState unreadState() const;
 
-	not_null<IndexedList*> indexed(Mode list = Mode::All);
-	not_null<const IndexedList*> indexed(Mode list = Mode::All) const;
+	not_null<IndexedList*> indexed(FilterId filterId = 0);
+	not_null<const IndexedList*> indexed() const;
 	not_null<PinnedList*> pinned();
 	not_null<const PinnedList*> pinned() const;
 
 private:
 	IndexedList _all;
-	IndexedList _important;
+	base::flat_map<FilterId, IndexedList> _other;
 	PinnedList _pinned;
 	UnreadState _unreadState;
 
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
index 957baa25e..1f6e0bb9c 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
@@ -528,9 +528,9 @@ void Widget::refreshDialog(Key key) {
 }
 
 void Widget::repaintDialogRow(
-		Mode list,
+		FilterId filterId,
 		not_null<Row*> row) {
-	_inner->repaintDialogRow(list, row);
+	_inner->repaintDialogRow(filterId, row);
 }
 
 void Widget::repaintDialogRow(RowDescriptor row) {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h
index 710f32c66..1fce349f1 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h
@@ -41,7 +41,6 @@ class ConnectionState;
 
 namespace Dialogs {
 
-enum class Mode;
 struct RowDescriptor;
 class Row;
 class FakeRow;
@@ -63,7 +62,7 @@ public:
 
 	void refreshDialog(Key key);
 	void removeDialog(Key key);
-	void repaintDialogRow(Mode list, not_null<Row*> row);
+	void repaintDialogRow(FilterId filterId, not_null<Row*> row);
 	void repaintDialogRow(RowDescriptor row);
 
 	void jumpToTop();
diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index a38a0fa73..ed84a2a63 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -314,8 +314,8 @@ struct Data {
 	bool AdaptiveForWide = true;
 	base::Observable<void> AdaptiveChanged;
 
-	bool DialogsModeEnabled = false;
-	Dialogs::Mode DialogsMode = Dialogs::Mode::All;
+	bool DialogsFiltersEnabled = false;
+	FilterId DialogsFilterId = 0;
 	bool ModerateModeEnabled = false;
 
 	bool ScreenIsLocked = false;
@@ -444,8 +444,8 @@ DefineVar(Global, Adaptive::ChatLayout, AdaptiveChatLayout);
 DefineVar(Global, bool, AdaptiveForWide);
 DefineRefVar(Global, base::Observable<void>, AdaptiveChanged);
 
-DefineVar(Global, bool, DialogsModeEnabled);
-DefineVar(Global, Dialogs::Mode, DialogsMode);
+DefineVar(Global, bool, DialogsFiltersEnabled);
+DefineVar(Global, FilterId, DialogsFilterId);
 DefineVar(Global, bool, ModerateModeEnabled);
 
 DefineVar(Global, bool, ScreenIsLocked);
diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h
index 9c4f41615..ad81566ba 100644
--- a/Telegram/SourceFiles/facades.h
+++ b/Telegram/SourceFiles/facades.h
@@ -18,10 +18,6 @@ namespace Data {
 struct FileOrigin;
 } // namespace Data
 
-namespace Dialogs {
-enum class Mode;
-} // namespace Dialogs
-
 namespace InlineBots {
 namespace Layout {
 class ItemBase;
@@ -154,8 +150,8 @@ DeclareVar(Adaptive::ChatLayout, AdaptiveChatLayout);
 DeclareVar(bool, AdaptiveForWide);
 DeclareRefVar(base::Observable<void>, AdaptiveChanged);
 
-DeclareVar(bool, DialogsModeEnabled);
-DeclareVar(Dialogs::Mode, DialogsMode);
+DeclareVar(bool, DialogsFiltersEnabled);
+DeclareVar(FilterId, DialogsFilterId);
 DeclareVar(bool, ModerateModeEnabled);
 
 DeclareVar(bool, ScreenIsLocked);
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index 7b0767027..da213ff5e 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -838,7 +838,7 @@ void History::setUnreadMentionsCount(int count) {
 	}
 	_unreadMentionsCount = count;
 	const auto has = (count > 0);
-	if (has != had && Global::DialogsModeEnabled()) {
+	if (has != had && Global::DialogsFiltersEnabled()) { // #TODO filters
 		Notify::historyMuteUpdated(this);
 		updateChatListEntry();
 	}
@@ -1912,8 +1912,6 @@ void History::clearFolder() {
 }
 
 void History::setFolderPointer(Data::Folder *folder) {
-	using Mode = Dialogs::Mode;
-
 	if (_folder == folder) {
 		return;
 	}
@@ -1922,23 +1920,24 @@ void History::setFolderPointer(Data::Folder *folder) {
 	}
 	const auto wasKnown = folderKnown();
 	const auto wasInList = inChatList();
-	const auto wasInImportant = wasInList && inChatList(Mode::Important);
-	if (wasInList) {
-		removeFromChatList(Mode::All);
-		if (wasInImportant) {
-			removeFromChatList(Mode::Important);
-		}
-	}
+	// #TODO filters
+	//const auto wasInImportant = wasInList && inChatList(Mode::Important);
+	//if (wasInList) {
+	//	removeFromChatList(Mode::All);
+	//	if (wasInImportant) {
+	//		removeFromChatList(Mode::Important);
+	//	}
+	//}
 	const auto was = _folder.value_or(nullptr);
 	_folder = folder;
 	if (was) {
 		was->unregisterOne(this);
 	}
 	if (wasInList) {
-		addToChatList(Mode::All);
-		if (wasInImportant) {
-			addToChatList(Mode::Important);
-		}
+		addToChatList(0);
+		//if (wasInImportant) { // #TODO filters
+		//	addToChatList(Mode::Important);
+		//}
 		owner().chatsListChanged(was);
 		owner().chatsListChanged(folder);
 	} else if (!wasKnown) {
@@ -2602,10 +2601,6 @@ bool History::shouldBeInChatList() const {
 		|| (lastMessage() != nullptr);
 }
 
-bool History::toImportant() const {
-	return !mute() || hasUnreadMentions();
-}
-
 void History::unknownMessageDeleted(MsgId messageId) {
 	if (_inboxReadBefore && messageId >= *_inboxReadBefore) {
 		owner().histories().requestDialogEntry(this);
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index 8ef86d070..9c321efaf 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -331,7 +331,6 @@ public:
 	int fixedOnTopIndex() const override;
 	void updateChatListExistence() override;
 	bool shouldBeInChatList() const override;
-	bool toImportant() const override;
 	int chatListUnreadCount() const override;
 	bool chatListUnreadMark() const override;
 	bool chatListMutedBadge() const override;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index b5a8dcfa9..68f38845a 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -2183,9 +2183,9 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams &param
 }
 
 void MainWidget::repaintDialogRow(
-		Dialogs::Mode list,
+		FilterId filterId,
 		not_null<Dialogs::Row*> row) {
-	_dialogs->repaintDialogRow(list, row);
+	_dialogs->repaintDialogRow(filterId, row);
 }
 
 void MainWidget::repaintDialogRow(Dialogs::RowDescriptor row) {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 61bbdab6e..928dd8aab 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -44,7 +44,6 @@ struct RowDescriptor;
 class Row;
 class Key;
 class Widget;
-enum class Mode;
 } // namespace Dialogs
 
 namespace Media {
@@ -136,7 +135,7 @@ public:
 
 	void refreshDialog(Dialogs::Key key);
 	void removeDialog(Dialogs::Key key);
-	void repaintDialogRow(Dialogs::Mode list, not_null<Dialogs::Row*> row);
+	void repaintDialogRow(FilterId filterId, not_null<Dialogs::Row*> row);
 	void repaintDialogRow(Dialogs::RowDescriptor row);
 
 	void windowShown();
diff --git a/Telegram/SourceFiles/settings/settings_codes.cpp b/Telegram/SourceFiles/settings/settings_codes.cpp
index e50471fa8..b86179618 100644
--- a/Telegram/SourceFiles/settings/settings_codes.cpp
+++ b/Telegram/SourceFiles/settings/settings_codes.cpp
@@ -70,7 +70,7 @@ auto GenerateCodes() {
 		Unexpected("Crashed in Settings!");
 	});
 	codes.emplace(qsl("workmode"), [](::Main::Session *session) {
-		auto text = Global::DialogsModeEnabled() ? qsl("Disable work mode?") : qsl("Enable work mode?");
+		auto text = Global::DialogsFiltersEnabled() ? qsl("Disable filters?") : qsl("Enable filters?");
 		Ui::show(Box<ConfirmBox>(text, [] {
 			Core::App().switchWorkMode();
 		}));
diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp
index 0418ce73a..26ef1bf9f 100644
--- a/Telegram/SourceFiles/storage/localstorage.cpp
+++ b/Telegram/SourceFiles/storage/localstorage.cpp
@@ -613,7 +613,7 @@ enum {
 	dbiHiddenPinnedMessages = 0x39,
 	dbiRecentEmoji = 0x3a,
 	dbiEmojiVariants = 0x3b,
-	dbiDialogsMode = 0x40,
+	dbiDialogsFilters = 0x40,
 	dbiModerateMode = 0x41,
 	dbiVideoVolume = 0x42,
 	dbiStickersRecentLimit = 0x43,
@@ -1167,20 +1167,20 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
 		}
 	} break;
 
-	case dbiDialogsMode: {
+	case dbiDialogsFilters: {
 		qint32 enabled, modeInt;
 		stream >> enabled >> modeInt;
 		if (!_checkStreamStatus(stream)) return false;
 
-		Global::SetDialogsModeEnabled(enabled == 1);
-		auto mode = Dialogs::Mode::All;
+		Global::SetDialogsFiltersEnabled(enabled == 1);
+		auto mode = FilterId(0);
 		if (enabled) {
-			mode = static_cast<Dialogs::Mode>(modeInt);
-			if (mode != Dialogs::Mode::All && mode != Dialogs::Mode::Important) {
-				mode = Dialogs::Mode::All;
+			mode = FilterId(modeInt);
+			if (mode == 1) { // #TODO filters
+
 			}
 		}
-		Global::SetDialogsMode(mode);
+		Global::SetDialogsFilterId(mode);
 	} break;
 
 	case dbiModerateMode: {
@@ -2140,7 +2140,7 @@ void _writeUserSettings() {
 	data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
 	data.stream << quint32(dbiSongVolume) << qint32(qRound(Global::SongVolume() * 1e6));
 	data.stream << quint32(dbiVideoVolume) << qint32(qRound(Global::VideoVolume() * 1e6));
-	data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode());
+	data.stream << quint32(dbiDialogsFilters) << qint32(Global::DialogsFiltersEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsFilterId());
 	data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0);
 	data.stream << quint32(dbiUseExternalVideoPlayer) << qint32(cUseExternalVideoPlayer());
 	data.stream << quint32(dbiCacheSettings) << qint64(_cacheTotalSizeLimit) << qint32(_cacheTotalTimeLimit) << qint64(_cacheBigFileTotalSizeLimit) << qint32(_cacheBigFileTotalTimeLimit);
diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp
index 0856bd074..fe82914c7 100644
--- a/Telegram/SourceFiles/window/window_session_controller.cpp
+++ b/Telegram/SourceFiles/window/window_session_controller.cpp
@@ -129,7 +129,7 @@ SessionController::SessionController(
 	) | rpl::filter([=](Data::Folder *folder) {
 		return (folder != nullptr)
 			&& (folder == _openedFolder.current())
-			&& folder->chatsList()->indexed(Global::DialogsMode())->empty();
+			&& folder->chatsList()->indexed()->empty();
 	}) | rpl::start_with_next([=](Data::Folder *folder) {
 		folder->updateChatListSortPosition();
 		closeFolder();