Make filtered lists independent from folders.

This commit is contained in:
John Preston 2020-03-09 15:17:56 +04:00
parent c305246d21
commit ca3419ef24
17 changed files with 98 additions and 56 deletions

View File

@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_channel.h"
#include "data/data_session.h"
#include "data/data_folder.h"
#include "dialogs/dialogs_main_list.h"
#include "main/main_session.h"
#include "apiwrap.h"
@ -179,6 +181,18 @@ ChatFilters::ChatFilters(not_null<Session*> owner) : _owner(owner) {
ChatFilter(2, "Unread", all | Flag::NoRead, {}, {}));
}
ChatFilters::~ChatFilters() = default;
not_null<Dialogs::MainList*> ChatFilters::chatsList(FilterId filterId) {
auto &pointer = _chatsLists[filterId];
if (!pointer) {
pointer = std::make_unique<Dialogs::MainList>(
filterId,
rpl::single(1));
}
return pointer.get();
}
void ChatFilters::load() {
load(false);
}
@ -285,21 +299,31 @@ void ChatFilters::applyRemove(int position) {
bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) {
const auto rulesChanged = (filter.flags() != updated.flags())
|| (filter.always() != updated.always());
|| (filter.always() != updated.always())
|| (filter.never() != updated.never());
if (rulesChanged) {
const auto list = _owner->chatsList()->indexed();
for (const auto &entry : *list) {
if (const auto history = entry->history()) {
const auto now = updated.contains(history);
const auto was = filter.contains(history);
if (now != was) {
if (now) {
history->addToChatList(filter.id());
} else {
history->removeFromChatList(filter.id());
}
const auto feedHistory = [&](not_null<History*> history) {
const auto now = updated.contains(history);
const auto was = filter.contains(history);
if (now != was) {
if (now) {
history->addToChatList(filter.id());
} else {
history->removeFromChatList(filter.id());
}
}
};
const auto feedList = [&](not_null<const Dialogs::MainList*> list) {
for (const auto &entry : *list->indexed()) {
if (const auto history = entry->history()) {
feedHistory(history);
}
}
};
feedList(_owner->chatsList());
const auto id = Data::Folder::kId;
if (const auto folder = _owner->folderLoaded(id)) {
feedList(folder->chatsList());
}
} else if (filter.title() == updated.title()) {
return false;

View File

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
namespace Dialogs {
class MainList;
} // namespace Dialogs
namespace Data {
class Session;
@ -63,6 +67,7 @@ private:
class ChatFilters final {
public:
explicit ChatFilters(not_null<Session*> owner);
~ChatFilters();
void load();
void apply(const MTPUpdate &update);
@ -75,6 +80,8 @@ public:
[[nodiscard]] auto refreshHistoryRequests() const
-> rpl::producer<not_null<History*>>;
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(FilterId filterId);
private:
void load(bool force);
bool applyOrder(const QVector<MTPint> &order);
@ -85,6 +92,7 @@ private:
const not_null<Session*> _owner;
std::vector<ChatFilter> _list;
base::flat_map<FilterId, std::unique_ptr<Dialogs::MainList>> _chatsLists;
rpl::event_stream<> _listChanged;
rpl::event_stream<not_null<History*>> _refreshHistoryRequests;
mtpRequestId _loadRequestId = 0;

View File

@ -57,7 +57,7 @@ rpl::producer<int> PinnedDialogsInFolderMaxValue(
Folder::Folder(not_null<Data::Session*> owner, FolderId id)
: Entry(owner, this)
, _id(id)
, _chatsList(PinnedDialogsInFolderMaxValue(&owner->session()))
, _chatsList(FilterId(), PinnedDialogsInFolderMaxValue(&owner->session()))
, _name(tr::lng_archived_name(tr::now)) {
indexNameParts();

View File

@ -139,8 +139,8 @@ int ScheduledMessages::count(not_null<History*> history) const {
}
void ScheduledMessages::sendNowSimpleMessage(
const MTPDupdateShortSentMessage &update,
not_null<HistoryItem*> local) {
const MTPDupdateShortSentMessage &update,
not_null<HistoryItem*> local) {
Expects(local->isSending());
Expects(local->isScheduled());
Expects(local->date() == kScheduledUntilOnlineTimestamp);

View File

@ -184,7 +184,7 @@ Session::Session(not_null<Main::Session*> session)
, _bigFileCache(Core::App().databases().get(
Local::cacheBigFilePath(),
Local::cacheBigFileSettings()))
, _chatsList(PinnedDialogsCountMaxValue(session))
, _chatsList(FilterId(), PinnedDialogsCountMaxValue(session))
, _contactsList(Dialogs::SortMode::Name)
, _contactsNoChatsList(Dialogs::SortMode::Name)
, _selfDestructTimer([=] { checkSelfDestructItems(); })

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_indexed_list.h"
#include "data/data_session.h"
#include "data/data_folder.h"
#include "data/data_chat_filters.h"
#include "mainwidget.h"
#include "main/main_session.h"
#include "history/history_item.h"
@ -92,16 +93,17 @@ void Entry::updateChatListSortPosition() {
updateChatListEntry();
return;
}
_sortKeyByDate = DialogPosFromDate(adjustedChatListTimeId());
const auto fixedIndex = fixedOnTopIndex();
_sortKeyInChatList = fixedIndex
? FixedOnTopDialogPos(fixedIndex)
: isPinnedDialog()
? PinnedDialogPos(_pinnedIndex)
: DialogPosFromDate(adjustedChatListTimeId());
: _sortKeyByDate;
if (needUpdateInChatList()) {
setChatListExistence(true);
} else {
_sortKeyInChatList = 0;
_sortKeyInChatList = _sortKeyByDate = 0;
}
}
@ -229,7 +231,9 @@ void Entry::updateChatListEntry() const {
}
not_null<IndexedList*> Entry::myChatsList(FilterId filterId) const {
return owner().chatsList(folder())->indexed(filterId);
return filterId
? owner().chatsFilters().chatsList(filterId)->indexed()
: owner().chatsList(folder())->indexed();
}
} // namespace Dialogs

View File

@ -31,9 +31,10 @@ struct RowsByLetter {
};
enum class SortMode {
Date = 0x00,
Name = 0x01,
Add = 0x02,
Complex = 0x00,
Date = 0x01,
Name = 0x02,
Add = 0x04,
};
struct PositionChange {
@ -120,6 +121,9 @@ public:
uint64 sortKeyInChatList() const {
return _sortKeyInChatList;
}
uint64 sortKeyByDate() const {
return _sortKeyByDate;
}
void updateChatListSortPosition();
void setChatListTimeId(TimeId date);
virtual void updateChatListExistence();
@ -199,6 +203,7 @@ private:
Dialogs::Key _key;
base::flat_map<FilterId, RowsByLetter> _chatListLinks;
uint64 _sortKeyInChatList = 0;
uint64 _sortKeyByDate = 0;
int _pinnedIndex = 0;
bool _isProxyPromoted = false;
TimeId _timeId = 0;

View File

@ -87,7 +87,7 @@ void IndexedList::movePinned(Row *row, int deltaSign) {
void IndexedList::peerNameChanged(
not_null<PeerData*> peer,
const base::flat_set<QChar> &oldLetters) {
Expects(_sortMode != SortMode::Date);
Expects(_sortMode != SortMode::Date && _sortMode != SortMode::Complex);
if (const auto history = peer->owner().historyLoaded(peer)) {
if (_sortMode == SortMode::Name) {
@ -102,7 +102,7 @@ void IndexedList::peerNameChanged(
FilterId filterId,
not_null<PeerData*> peer,
const base::flat_set<QChar> &oldLetters) {
Expects(_sortMode == SortMode::Date);
Expects(_sortMode == SortMode::Date || _sortMode == SortMode::Complex);
if (const auto history = peer->owner().historyLoaded(peer)) {
adjustNames(filterId, history, oldLetters);
@ -165,7 +165,7 @@ void IndexedList::adjustNames(
}
}
for (auto ch : toRemove) {
if (_sortMode == SortMode::Date) {
if (_sortMode == SortMode::Date || _sortMode == SortMode::Complex) {
history->removeChatListEntryByLetter(filterId, ch);
}
if (auto it = _index.find(ch); it != _index.cend()) {
@ -178,7 +178,7 @@ void IndexedList::adjustNames(
j = _index.emplace(ch, _sortMode).first;
}
auto row = j->second.addToEnd(key);
if (_sortMode == SortMode::Date) {
if (_sortMode == SortMode::Date || _sortMode == SortMode::Complex) {
history->addChatListEntryByLetter(filterId, ch, row);
}
}

View File

@ -26,12 +26,12 @@ public:
// row must belong to this indexed list all().
void movePinned(Row *row, int deltaSign);
// For sortMode != SortMode::Date
// For sortMode != SortMode::Date && != Complex
void peerNameChanged(
not_null<PeerData*> peer,
const base::flat_set<QChar> &oldChars);
//For sortMode == SortMode::Date
//For sortMode == SortMode::Date || == Complex
void peerNameChanged(
FilterId filterId,
not_null<PeerData*> peer,

View File

@ -440,6 +440,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
Layout::RowPainter::paint(
p,
row,
_filterId,
fullWidth,
isActive,
isSelected,
@ -565,6 +566,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
Layout::RowPainter::paint(
p,
_filterResults[from],
_filterId,
fullWidth,
active,
selected,
@ -1680,7 +1682,9 @@ void InnerWidget::updateSelectedRow(Key key) {
}
not_null<IndexedList*> InnerWidget::shownDialogs() const {
return session().data().chatsList(_openedFolder)->indexed(_filterId);
return _filterId
? session().data().chatsFilters().chatsList(_filterId)->indexed()
: session().data().chatsList(_openedFolder)->indexed();
}
void InnerWidget::leaveEventHook(QEvent *e) {

View File

@ -613,6 +613,7 @@ void paintUnreadCount(
void RowPainter::paint(
Painter &p,
not_null<const Row*> row,
int filterId,
int fullWidth,
bool active,
bool selected,
@ -668,6 +669,7 @@ void RowPainter::paint(
const auto displayPinnedIcon = !displayUnreadCounter
&& !displayMentionBadge
&& !displayUnreadMark
&& !filterId
&& entry->isPinnedDialog()
&& !entry->fixedOnTopIndex();

View File

@ -29,6 +29,7 @@ public:
static void paint(
Painter &p,
not_null<const Row*> row,
int filterId,
int fullWidth,
bool active,
bool selected,

View File

@ -32,7 +32,7 @@ not_null<Row*> List::addToEnd(Key key) {
std::make_unique<Row>(key, _rows.size())
).first->second.get();
_rows.emplace_back(result);
if (_sortMode == SortMode::Date) {
if (_sortMode == SortMode::Date || _sortMode == SortMode::Complex) {
adjustByDate(result);
}
return result;
@ -82,20 +82,20 @@ void List::adjustByName(not_null<Row*> row) {
}
void List::adjustByDate(not_null<Row*> row) {
Expects(_sortMode == SortMode::Date);
Expects(_sortMode == SortMode::Date || _sortMode == SortMode::Complex);
const auto key = row->sortKey();
const auto key = row->sortKey(_sortMode);
const auto index = row->pos();
const auto i = _rows.begin() + index;
const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
return (row->sortKey() <= key);
return (row->sortKey(_sortMode) <= key);
});
if (before != i + 1) {
rotate(i, i + 1, before);
} else {
const auto from = std::make_reverse_iterator(i);
const auto after = std::find_if(from, _rows.rend(), [&](Row *row) {
return (row->sortKey() >= key);
return (row->sortKey(_sortMode) >= key);
}).base();
if (after != i) {
rotate(after, i, i + 1);

View File

@ -12,8 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Dialogs {
MainList::MainList(rpl::producer<int> pinnedLimit)
: _all(SortMode::Date)
MainList::MainList(FilterId filterId, rpl::producer<int> pinnedLimit)
: _filterId(filterId)
, _all(filterId ? SortMode::Date : SortMode::Complex)
, _pinned(1) {
_unreadState.known = true;
@ -28,10 +29,7 @@ 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(FilterId(), peer, oldLetters);
for (auto &[filterId, list] : _other) {
list.peerNameChanged(filterId, peer, oldLetters);
}
_all.peerNameChanged(_filterId, peer, oldLetters);
}, _lifetime);
}
@ -49,7 +47,6 @@ void MainList::setLoaded(bool loaded) {
void MainList::clear() {
_all.clear();
_other.clear();
_unreadState = UnreadState();
}
@ -73,15 +70,8 @@ UnreadState MainList::unreadState() const {
return _unreadState;
}
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<IndexedList*> MainList::indexed() {
return &_all;
}
not_null<const IndexedList*> MainList::indexed() const {

View File

@ -14,7 +14,7 @@ namespace Dialogs {
class MainList final {
public:
explicit MainList(rpl::producer<int> pinnedLimit);
MainList(FilterId filterId, rpl::producer<int> pinnedLimit);
bool empty() const;
bool loaded() const;
@ -29,14 +29,14 @@ public:
bool added);
[[nodiscard]] UnreadState unreadState() const;
not_null<IndexedList*> indexed(FilterId filterId = 0);
not_null<IndexedList*> indexed();
not_null<const IndexedList*> indexed() const;
not_null<PinnedList*> pinned();
not_null<const PinnedList*> pinned() const;
private:
FilterId _filterId = 0;
IndexedList _all;
base::flat_map<FilterId, IndexedList> _other;
PinnedList _pinned;
UnreadState _unreadState;

View File

@ -220,8 +220,10 @@ Row::Row(Key key, int pos) : _id(key), _pos(pos) {
}
}
uint64 Row::sortKey() const {
return _id.entry()->sortKeyInChatList();
uint64 Row::sortKey(SortMode mode) const {
return (mode == SortMode::Complex)
? _id.entry()->sortKeyInChatList()
: _id.entry()->sortKeyByDate();
}
void Row::validateListEntryCache() const {

View File

@ -23,6 +23,8 @@ namespace Layout {
class RowPainter;
} // namespace Layout
enum class SortMode;
class BasicRow {
public:
BasicRow();
@ -88,7 +90,7 @@ public:
int pos() const {
return _pos;
}
uint64 sortKey() const;
uint64 sortKey(SortMode mode) const;
void validateListEntryCache() const;
const Ui::Text::String &listEntryCache() const {