mirror of https://github.com/procxx/kepka.git
Count unread messages in Dialogs::MainList.
This commit is contained in:
parent
9636617798
commit
38a744fe5b
|
@ -303,14 +303,16 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) {
|
||||||
|| (filter.always() != updated.always())
|
|| (filter.always() != updated.always())
|
||||||
|| (filter.never() != updated.never());
|
|| (filter.never() != updated.never());
|
||||||
if (rulesChanged) {
|
if (rulesChanged) {
|
||||||
|
const auto id = filter.id();
|
||||||
|
const auto filterList = _owner->chatsFilters().chatsList(id);
|
||||||
const auto feedHistory = [&](not_null<History*> history) {
|
const auto feedHistory = [&](not_null<History*> history) {
|
||||||
const auto now = updated.contains(history);
|
const auto now = updated.contains(history);
|
||||||
const auto was = filter.contains(history);
|
const auto was = filter.contains(history);
|
||||||
if (now != was) {
|
if (now != was) {
|
||||||
if (now) {
|
if (now) {
|
||||||
history->addToChatList(filter.id());
|
history->addToChatList(id, filterList);
|
||||||
} else {
|
} else {
|
||||||
history->removeFromChatList(filter.id());
|
history->removeFromChatList(id, filterList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -322,8 +324,7 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
feedList(_owner->chatsList());
|
feedList(_owner->chatsList());
|
||||||
const auto id = Data::Folder::kId;
|
if (const auto folder = _owner->folderLoaded(Data::Folder::kId)) {
|
||||||
if (const auto folder = _owner->folderLoaded(id)) {
|
|
||||||
feedList(folder->chatsList());
|
feedList(folder->chatsList());
|
||||||
}
|
}
|
||||||
} else if (filter.title() == updated.title()) {
|
} else if (filter.title() == updated.title()) {
|
||||||
|
|
|
@ -72,6 +72,22 @@ Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
|
_chatsList.setAllAreMuted(true);
|
||||||
|
|
||||||
|
_chatsList.unreadStateChanges(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return inChatList();
|
||||||
|
}) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
||||||
|
++_chatListViewVersion;
|
||||||
|
notifyUnreadStateChange(old);
|
||||||
|
updateChatListEntry();
|
||||||
|
}, _lifetime);
|
||||||
|
|
||||||
|
_chatsList.fullSize().changes(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateChatListEntry();
|
||||||
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderId Folder::id() const {
|
FolderId Folder::id() const {
|
||||||
|
@ -108,7 +124,7 @@ void Folder::indexNameParts() {
|
||||||
void Folder::registerOne(not_null<History*> history) {
|
void Folder::registerOne(not_null<History*> history) {
|
||||||
if (_chatsList.indexed()->size() == 1) {
|
if (_chatsList.indexed()->size() == 1) {
|
||||||
updateChatListSortPosition();
|
updateChatListSortPosition();
|
||||||
if (!_cloudUnread.known) {
|
if (!_chatsList.cloudUnreadKnown()) {
|
||||||
owner().histories().requestDialogEntry(this);
|
owner().histories().requestDialogEntry(this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -291,29 +307,6 @@ void Folder::paintUserpic(
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Folder::chatsListLoaded() const {
|
|
||||||
return _chatsList.loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setChatsListLoaded(bool loaded) {
|
|
||||||
if (_chatsList.loaded() == loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto notifier = unreadStateChangeNotifier(true);
|
|
||||||
_chatsList.setLoaded(loaded);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::setCloudChatsListSize(int size) {
|
|
||||||
_cloudChatsListSize = size;
|
|
||||||
updateChatListEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Folder::chatsListSize() const {
|
|
||||||
return std::max(
|
|
||||||
_chatsList.indexed()->size(),
|
|
||||||
_chatsList.loaded() ? 0 : _cloudChatsListSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<not_null<History*>> &Folder::lastHistories() const {
|
const std::vector<not_null<History*>> &Folder::lastHistories() const {
|
||||||
return _lastHistories;
|
return _lastHistories;
|
||||||
}
|
}
|
||||||
|
@ -333,7 +326,7 @@ TimeId Folder::adjustedChatListTimeId() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::applyDialog(const MTPDdialogFolder &data) {
|
void Folder::applyDialog(const MTPDdialogFolder &data) {
|
||||||
updateCloudUnread(data);
|
_chatsList.updateCloudUnread(data);
|
||||||
if (const auto peerId = peerFromMTP(data.vpeer())) {
|
if (const auto peerId = peerFromMTP(data.vpeer())) {
|
||||||
const auto history = owner().history(peerId);
|
const auto history = owner().history(peerId);
|
||||||
const auto fullId = FullMsgId(
|
const auto fullId = FullMsgId(
|
||||||
|
@ -349,39 +342,6 @@ void Folder::applyDialog(const MTPDdialogFolder &data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::updateCloudUnread(const MTPDdialogFolder &data) {
|
|
||||||
const auto notifier = unreadStateChangeNotifier(!_chatsList.loaded());
|
|
||||||
|
|
||||||
_cloudUnread.messages = data.vunread_muted_messages_count().v
|
|
||||||
+ data.vunread_unmuted_messages_count().v;
|
|
||||||
_cloudUnread.chats = data.vunread_muted_peers_count().v
|
|
||||||
+ data.vunread_unmuted_peers_count().v;
|
|
||||||
finalizeCloudUnread();
|
|
||||||
|
|
||||||
_cloudUnread.known = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::finalizeCloudUnread() {
|
|
||||||
// Cloud state for archive folder always counts everything as muted.
|
|
||||||
_cloudUnread.messagesMuted = _cloudUnread.messages;
|
|
||||||
_cloudUnread.chatsMuted = _cloudUnread.chats;
|
|
||||||
|
|
||||||
// We don't know the real value of marked chats counts in _cloudUnread.
|
|
||||||
_cloudUnread.marksMuted = _cloudUnread.marks = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialogs::UnreadState Folder::chatListUnreadState() const {
|
|
||||||
const auto localUnread = _chatsList.unreadState();
|
|
||||||
auto result = _chatsList.loaded() ? localUnread : _cloudUnread;
|
|
||||||
result.messagesMuted = result.messages;
|
|
||||||
result.chatsMuted = result.chats;
|
|
||||||
|
|
||||||
// We don't know the real value of marked chats counts in _cloudUnread.
|
|
||||||
result.marksMuted = result.marks = localUnread.marks;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
const auto folderId = data.vfolder_id().value_or_empty();
|
const auto folderId = data.vfolder_id().value_or_empty();
|
||||||
if (folderId != 0) {
|
if (folderId != 0) {
|
||||||
|
@ -390,48 +350,6 @@ void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) {
|
||||||
owner().setChatPinned(this, data.is_pinned());
|
owner().setChatPinned(this, data.is_pinned());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::unreadStateChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &wasState,
|
|
||||||
const Dialogs::UnreadState &nowState) {
|
|
||||||
if (const auto history = key.history()) {
|
|
||||||
if (wasState.empty() != nowState.empty()) {
|
|
||||||
++_chatListViewVersion;
|
|
||||||
updateChatListEntry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto updateCloudUnread = _cloudUnread.known && wasState.known;
|
|
||||||
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
|
||||||
const auto notifier = unreadStateChangeNotifier(notify);
|
|
||||||
|
|
||||||
_chatsList.unreadStateChanged(wasState, nowState);
|
|
||||||
if (updateCloudUnread) {
|
|
||||||
Assert(nowState.known);
|
|
||||||
_cloudUnread += nowState - wasState;
|
|
||||||
finalizeCloudUnread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::unreadEntryChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &state,
|
|
||||||
bool added) {
|
|
||||||
const auto updateCloudUnread = _cloudUnread.known && state.known;
|
|
||||||
const auto notify = _chatsList.loaded() || updateCloudUnread;
|
|
||||||
const auto notifier = unreadStateChangeNotifier(notify);
|
|
||||||
|
|
||||||
_chatsList.unreadEntryChanged(state, added);
|
|
||||||
if (updateCloudUnread) {
|
|
||||||
if (added) {
|
|
||||||
_cloudUnread += state;
|
|
||||||
} else {
|
|
||||||
_cloudUnread -= state;
|
|
||||||
}
|
|
||||||
finalizeCloudUnread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #feed
|
// #feed
|
||||||
//MessagePosition Folder::unreadPosition() const {
|
//MessagePosition Folder::unreadPosition() const {
|
||||||
// return _unreadPosition.current();
|
// return _unreadPosition.current();
|
||||||
|
@ -457,6 +375,10 @@ int Folder::chatListUnreadCount() const {
|
||||||
: state.chats);
|
: state.chats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialogs::UnreadState Folder::chatListUnreadState() const {
|
||||||
|
return _chatsList.unreadState();
|
||||||
|
}
|
||||||
|
|
||||||
bool Folder::chatListUnreadMark() const {
|
bool Folder::chatListUnreadMark() const {
|
||||||
return false; // #feed unread mark
|
return false; // #feed unread mark
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,16 +45,6 @@ public:
|
||||||
//MessagePosition unreadPosition() const; // #feed
|
//MessagePosition unreadPosition() const; // #feed
|
||||||
//rpl::producer<MessagePosition> unreadPositionChanges() const; // #feed
|
//rpl::producer<MessagePosition> unreadPositionChanges() const; // #feed
|
||||||
|
|
||||||
void updateCloudUnread(const MTPDdialogFolder &data);
|
|
||||||
void unreadStateChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &wasState,
|
|
||||||
const Dialogs::UnreadState &nowState);
|
|
||||||
void unreadEntryChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &state,
|
|
||||||
bool added);
|
|
||||||
|
|
||||||
TimeId adjustedChatListTimeId() const override;
|
TimeId adjustedChatListTimeId() const override;
|
||||||
|
|
||||||
int fixedOnTopIndex() const override;
|
int fixedOnTopIndex() const override;
|
||||||
|
@ -85,11 +75,6 @@ public:
|
||||||
const style::color &overrideBg,
|
const style::color &overrideBg,
|
||||||
const style::color &overrideFg) const;
|
const style::color &overrideFg) const;
|
||||||
|
|
||||||
bool chatsListLoaded() const;
|
|
||||||
void setChatsListLoaded(bool loaded = true);
|
|
||||||
void setCloudChatsListSize(int size);
|
|
||||||
|
|
||||||
int chatsListSize() const;
|
|
||||||
const std::vector<not_null<History*>> &lastHistories() const;
|
const std::vector<not_null<History*>> &lastHistories() const;
|
||||||
uint32 chatListViewVersion() const;
|
uint32 chatListViewVersion() const;
|
||||||
|
|
||||||
|
@ -99,7 +84,6 @@ private:
|
||||||
void computeChatListMessage();
|
void computeChatListMessage();
|
||||||
|
|
||||||
void reorderLastHistories();
|
void reorderLastHistories();
|
||||||
void finalizeCloudUnread();
|
|
||||||
|
|
||||||
void paintUserpic(
|
void paintUserpic(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
@ -116,8 +100,6 @@ private:
|
||||||
base::flat_set<QString> _nameWords;
|
base::flat_set<QString> _nameWords;
|
||||||
base::flat_set<QChar> _nameFirstLetters;
|
base::flat_set<QChar> _nameFirstLetters;
|
||||||
|
|
||||||
Dialogs::UnreadState _cloudUnread;
|
|
||||||
int _cloudChatsListSize = 0;
|
|
||||||
std::vector<not_null<History*>> _lastHistories;
|
std::vector<not_null<History*>> _lastHistories;
|
||||||
HistoryItem *_chatListMessage = nullptr;
|
HistoryItem *_chatListMessage = nullptr;
|
||||||
uint32 _chatListViewVersion = 0;
|
uint32 _chatListViewVersion = 0;
|
||||||
|
|
|
@ -214,6 +214,11 @@ Session::Session(not_null<Main::Session*> session)
|
||||||
setupChannelLeavingViewer();
|
setupChannelLeavingViewer();
|
||||||
setupPeerNameViewer();
|
setupPeerNameViewer();
|
||||||
setupUserIsContactViewer();
|
setupUserIsContactViewer();
|
||||||
|
|
||||||
|
_chatsList.unreadStateChanges(
|
||||||
|
) | rpl::start_with_next([] {
|
||||||
|
Notify::unreadCounterUpdated();
|
||||||
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clear() {
|
void Session::clear() {
|
||||||
|
@ -833,7 +838,7 @@ void Session::chatsListChanged(Data::Folder *folder) {
|
||||||
|
|
||||||
void Session::chatsListDone(Data::Folder *folder) {
|
void Session::chatsListDone(Data::Folder *folder) {
|
||||||
if (folder) {
|
if (folder) {
|
||||||
folder->setChatsListLoaded();
|
folder->chatsList()->setLoaded();
|
||||||
} else {
|
} else {
|
||||||
_chatsList.setLoaded();
|
_chatsList.setLoaded();
|
||||||
}
|
}
|
||||||
|
@ -1506,7 +1511,7 @@ void Session::applyDialogs(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (requestFolder && count) {
|
if (requestFolder && count) {
|
||||||
requestFolder->setCloudChatsListSize(*count);
|
requestFolder->chatsList()->setCloudListSize(*count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2016,35 +2021,6 @@ bool Session::computeUnreadBadgeMuted(
|
||||||
: (state.chatsMuted >= state.chats));
|
: (state.chatsMuted >= state.chats));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::unreadStateChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &wasState) {
|
|
||||||
Expects(key.entry()->folderKnown());
|
|
||||||
Expects(key.entry()->inChatList());
|
|
||||||
|
|
||||||
const auto nowState = key.entry()->chatListUnreadState();
|
|
||||||
if (const auto folder = key.entry()->folder()) {
|
|
||||||
folder->unreadStateChanged(key, wasState, nowState);
|
|
||||||
} else {
|
|
||||||
_chatsList.unreadStateChanged(wasState, nowState);
|
|
||||||
}
|
|
||||||
Notify::unreadCounterUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::unreadEntryChanged(const Dialogs::Key &key, bool added) {
|
|
||||||
Expects(key.entry()->folderKnown());
|
|
||||||
|
|
||||||
const auto state = key.entry()->chatListUnreadState();
|
|
||||||
if (!state.empty()) {
|
|
||||||
if (const auto folder = key.entry()->folder()) {
|
|
||||||
folder->unreadEntryChanged(key, state, added);
|
|
||||||
} else {
|
|
||||||
_chatsList.unreadEntryChanged(state, added);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Notify::unreadCounterUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::selfDestructIn(not_null<HistoryItem*> item, crl::time delay) {
|
void Session::selfDestructIn(not_null<HistoryItem*> item, crl::time delay) {
|
||||||
_selfDestructItems.push_back(item->fullId());
|
_selfDestructItems.push_back(item->fullId());
|
||||||
if (!_selfDestructTimer.isActive()
|
if (!_selfDestructTimer.isActive()
|
||||||
|
@ -3347,33 +3323,42 @@ auto Session::refreshChatListEntry(
|
||||||
Dialogs::Key key,
|
Dialogs::Key key,
|
||||||
FilterId filterIdForResult)
|
FilterId filterIdForResult)
|
||||||
-> RefreshChatListEntryResult {
|
-> RefreshChatListEntryResult {
|
||||||
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
|
|
||||||
const auto entry = key.entry();
|
const auto entry = key.entry();
|
||||||
const auto history = key.history();
|
const auto history = key.history();
|
||||||
|
const auto mainList = chatsList(entry->folder());
|
||||||
auto mainListResult = RefreshChatListEntryResult();
|
auto mainListResult = RefreshChatListEntryResult();
|
||||||
mainListResult.changed = !entry->inChatList();
|
mainListResult.changed = !entry->inChatList();
|
||||||
if (mainListResult.changed) {
|
if (mainListResult.changed) {
|
||||||
const auto mainRow = entry->addToChatList(0);
|
const auto mainRow = entry->addToChatList(0, mainList);
|
||||||
_contactsNoChatsList.del(key, mainRow);
|
_contactsNoChatsList.del(key, mainRow);
|
||||||
} else {
|
} else {
|
||||||
mainListResult.moved = entry->adjustByPosInChatList(0);
|
mainListResult.moved = entry->adjustByPosInChatList(0, mainList);
|
||||||
}
|
}
|
||||||
auto result = filterIdForResult
|
auto result = filterIdForResult
|
||||||
? RefreshChatListEntryResult()
|
? RefreshChatListEntryResult()
|
||||||
: mainListResult;
|
: mainListResult;
|
||||||
|
if (!history) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
for (const auto &filter : _chatsFilters->list()) {
|
for (const auto &filter : _chatsFilters->list()) {
|
||||||
const auto id = filter.id();
|
const auto id = filter.id();
|
||||||
|
const auto filterList = chatsFilters().chatsList(id);
|
||||||
auto filterResult = RefreshChatListEntryResult();
|
auto filterResult = RefreshChatListEntryResult();
|
||||||
if (history && filter.contains(history)) {
|
if (filter.contains(history)) {
|
||||||
filterResult.changed = !entry->inChatList(id);
|
filterResult.changed = !entry->inChatList(id);
|
||||||
if (filterResult.changed) {
|
if (filterResult.changed) {
|
||||||
entry->addToChatList(id);
|
entry->addToChatList(id, filterList);
|
||||||
} else {
|
} else {
|
||||||
filterResult.moved = entry->adjustByPosInChatList(id);
|
filterResult.moved = entry->adjustByPosInChatList(
|
||||||
|
id,
|
||||||
|
filterList);
|
||||||
}
|
}
|
||||||
} else if (entry->inChatList(id)) {
|
} else if (entry->inChatList(id)) {
|
||||||
entry->removeFromChatList(id);
|
entry->removeFromChatList(id, filterList);
|
||||||
filterResult.changed = true;
|
filterResult.changed = true;
|
||||||
}
|
}
|
||||||
if (id == filterIdForResult) {
|
if (id == filterIdForResult) {
|
||||||
|
@ -3387,9 +3372,17 @@ void Session::removeChatListEntry(Dialogs::Key key) {
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
|
|
||||||
const auto entry = key.entry();
|
const auto entry = key.entry();
|
||||||
entry->removeFromChatList(0);
|
if (!entry->inChatList()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assert(entry->folderKnown());
|
||||||
|
const auto mainList = chatsList(entry->folder());
|
||||||
|
entry->removeFromChatList(0, mainList);
|
||||||
for (const auto &filter : _chatsFilters->list()) {
|
for (const auto &filter : _chatsFilters->list()) {
|
||||||
entry->removeFromChatList(filter.id());
|
const auto id = filter.id();
|
||||||
|
if (entry->inChatList(id)) {
|
||||||
|
entry->removeFromChatList(id, chatsFilters().chatsList(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_contactsList.contains(key)) {
|
if (_contactsList.contains(key)) {
|
||||||
if (!_contactsNoChatsList.contains(key)) {
|
if (!_contactsNoChatsList.contains(key)) {
|
||||||
|
|
|
@ -449,11 +449,6 @@ public:
|
||||||
bool unreadBadgeMutedIgnoreOne(const Dialogs::Key &key) const;
|
bool unreadBadgeMutedIgnoreOne(const Dialogs::Key &key) const;
|
||||||
int unreadOnlyMutedBadge() const;
|
int unreadOnlyMutedBadge() const;
|
||||||
|
|
||||||
void unreadStateChanged(
|
|
||||||
const Dialogs::Key &key,
|
|
||||||
const Dialogs::UnreadState &wasState);
|
|
||||||
void unreadEntryChanged(const Dialogs::Key &key, bool added);
|
|
||||||
|
|
||||||
void selfDestructIn(not_null<HistoryItem*> item, crl::time delay);
|
void selfDestructIn(not_null<HistoryItem*> item, crl::time delay);
|
||||||
|
|
||||||
[[nodiscard]] not_null<PhotoData*> photo(PhotoId id);
|
[[nodiscard]] not_null<PhotoData*> photo(PhotoId id);
|
||||||
|
|
|
@ -112,7 +112,15 @@ void Entry::updateChatListExistence() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::notifyUnreadStateChange(const UnreadState &wasState) {
|
void Entry::notifyUnreadStateChange(const UnreadState &wasState) {
|
||||||
owner().unreadStateChanged(_key, wasState);
|
Expects(folderKnown());
|
||||||
|
Expects(inChatList());
|
||||||
|
|
||||||
|
const auto nowState = chatListUnreadState();
|
||||||
|
owner().chatsList(folder())->unreadStateChanged(wasState, nowState);
|
||||||
|
auto &filters = owner().chatsFilters();
|
||||||
|
for (const auto &[filterId, links] : _chatListLinks) {
|
||||||
|
filters.chatsList(filterId)->unreadStateChanged(wasState, nowState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::setChatListExistence(bool exists) {
|
void Entry::setChatListExistence(bool exists) {
|
||||||
|
@ -154,11 +162,13 @@ Row *Entry::maybeMainChatListLink(FilterId filterId) const {
|
||||||
return links ? links->main.get() : nullptr;
|
return links ? links->main.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionChange Entry::adjustByPosInChatList(FilterId filterId) {
|
PositionChange Entry::adjustByPosInChatList(
|
||||||
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list) {
|
||||||
const auto links = chatListLinks(filterId);
|
const auto links = chatListLinks(filterId);
|
||||||
Assert(links != nullptr);
|
Assert(links != nullptr);
|
||||||
const auto from = links->main->pos();
|
const auto from = links->main->pos();
|
||||||
myChatsList(filterId)->adjustByDate(*links);
|
list->indexed()->adjustByDate(*links);
|
||||||
const auto to = links->main->pos();
|
const auto to = links->main->pos();
|
||||||
return { from, to };
|
return { from, to };
|
||||||
}
|
}
|
||||||
|
@ -175,30 +185,27 @@ int Entry::posInChatList(FilterId filterId) const {
|
||||||
return mainChatListLink(filterId)->pos();
|
return mainChatListLink(filterId)->pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Row*> Entry::addToChatList(FilterId filterId) {
|
not_null<Row*> Entry::addToChatList(
|
||||||
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list) {
|
||||||
if (const auto main = maybeMainChatListLink(filterId)) {
|
if (const auto main = maybeMainChatListLink(filterId)) {
|
||||||
return main;
|
return main;
|
||||||
}
|
}
|
||||||
const auto result = _chatListLinks.emplace(
|
return _chatListLinks.emplace(
|
||||||
filterId,
|
filterId,
|
||||||
myChatsList(filterId)->addToEnd(_key)
|
list->addEntry(_key)
|
||||||
).first->second.main;
|
).first->second.main;
|
||||||
if (!filterId) {
|
|
||||||
owner().unreadEntryChanged(_key, true);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::removeFromChatList(FilterId filterId) {
|
void Entry::removeFromChatList(
|
||||||
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list) {
|
||||||
const auto i = _chatListLinks.find(filterId);
|
const auto i = _chatListLinks.find(filterId);
|
||||||
if (i == end(_chatListLinks)) {
|
if (i == end(_chatListLinks)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
myChatsList(filterId)->del(_key);
|
|
||||||
_chatListLinks.erase(i);
|
_chatListLinks.erase(i);
|
||||||
if (!filterId) {
|
list->removeEntry(_key);
|
||||||
owner().unreadEntryChanged(_key, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) {
|
void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) {
|
||||||
|
@ -230,10 +237,4 @@ void Entry::updateChatListEntry() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<IndexedList*> Entry::myChatsList(FilterId filterId) const {
|
|
||||||
return filterId
|
|
||||||
? owner().chatsFilters().chatsList(filterId)->indexed()
|
|
||||||
: owner().chatsList(folder())->indexed();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dialogs
|
} // namespace Dialogs
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace Dialogs {
|
||||||
|
|
||||||
class Row;
|
class Row;
|
||||||
class IndexedList;
|
class IndexedList;
|
||||||
|
class MainList;
|
||||||
|
|
||||||
struct RowsByLetter {
|
struct RowsByLetter {
|
||||||
not_null<Row*> main;
|
not_null<Row*> main;
|
||||||
|
@ -97,13 +98,19 @@ public:
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
|
||||||
PositionChange adjustByPosInChatList(FilterId filterId);
|
PositionChange adjustByPosInChatList(
|
||||||
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list);
|
||||||
[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
|
[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
|
||||||
return _chatListLinks.contains(filterId);
|
return _chatListLinks.contains(filterId);
|
||||||
}
|
}
|
||||||
[[nodiscard]] int posInChatList(FilterId filterId) const;
|
[[nodiscard]] int posInChatList(FilterId filterId) const;
|
||||||
not_null<Row*> addToChatList(FilterId filterId);
|
not_null<Row*> addToChatList(
|
||||||
void removeFromChatList(FilterId filterId);
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list);
|
||||||
|
void removeFromChatList(
|
||||||
|
FilterId filterId,
|
||||||
|
not_null<MainList*> list);
|
||||||
void removeChatListEntryByLetter(FilterId filterId, QChar letter);
|
void removeChatListEntryByLetter(FilterId filterId, QChar letter);
|
||||||
void addChatListEntryByLetter(
|
void addChatListEntryByLetter(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
|
@ -176,6 +183,7 @@ public:
|
||||||
mutable Ui::Text::String lastItemTextCache;
|
mutable Ui::Text::String lastItemTextCache;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void notifyUnreadStateChange(const UnreadState &wasState);
|
||||||
auto unreadStateChangeNotifier(bool required) {
|
auto unreadStateChangeNotifier(bool required) {
|
||||||
const auto notify = required && inChatList();
|
const auto notify = required && inChatList();
|
||||||
const auto wasState = notify ? chatListUnreadState() : UnreadState();
|
const auto wasState = notify ? chatListUnreadState() : UnreadState();
|
||||||
|
@ -189,16 +197,12 @@ protected:
|
||||||
private:
|
private:
|
||||||
virtual void changedChatListPinHook();
|
virtual void changedChatListPinHook();
|
||||||
|
|
||||||
void notifyUnreadStateChange(const UnreadState &wasState);
|
|
||||||
|
|
||||||
void setChatListExistence(bool exists);
|
void setChatListExistence(bool exists);
|
||||||
RowsByLetter *chatListLinks(FilterId filterId);
|
RowsByLetter *chatListLinks(FilterId filterId);
|
||||||
const RowsByLetter *chatListLinks(FilterId filterId) const;
|
const RowsByLetter *chatListLinks(FilterId filterId) const;
|
||||||
not_null<Row*> mainChatListLink(FilterId filterId) const;
|
not_null<Row*> mainChatListLink(FilterId filterId) const;
|
||||||
Row *maybeMainChatListLink(FilterId filterId) const;
|
Row *maybeMainChatListLink(FilterId filterId) const;
|
||||||
|
|
||||||
not_null<IndexedList*> myChatsList(FilterId filterId) const;
|
|
||||||
|
|
||||||
not_null<Data::Session*> _owner;
|
not_null<Data::Session*> _owner;
|
||||||
Dialogs::Key _key;
|
Dialogs::Key _key;
|
||||||
base::flat_map<FilterId, RowsByLetter> _chatListLinks;
|
base::flat_map<FilterId, RowsByLetter> _chatListLinks;
|
||||||
|
|
|
@ -1728,7 +1728,9 @@ void InnerWidget::fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu) {
|
||||||
|
|
||||||
void InnerWidget::fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu) {
|
void InnerWidget::fillArchiveSearchMenu(not_null<Ui::PopupMenu*> menu) {
|
||||||
const auto folder = session().data().folderLoaded(Data::Folder::kId);
|
const auto folder = session().data().folderLoaded(Data::Folder::kId);
|
||||||
if (!folder || !folder->chatsListSize() || _searchInChat) {
|
if (!folder
|
||||||
|
|| !folder->chatsList()->fullSize().current()
|
||||||
|
|| _searchInChat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto skip = session().settings().skipArchiveInSearch();
|
const auto skip = session().settings().skipArchiveInSearch();
|
||||||
|
|
|
@ -42,32 +42,149 @@ bool MainList::loaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainList::setLoaded(bool loaded) {
|
void MainList::setLoaded(bool loaded) {
|
||||||
|
if (_loaded == loaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto notifier = unreadStateChangeNotifier(true);
|
||||||
_loaded = loaded;
|
_loaded = loaded;
|
||||||
|
recomputeFullListSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::setAllAreMuted(bool allAreMuted) {
|
||||||
|
if (_allAreMuted == allAreMuted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto notifier = unreadStateChangeNotifier(true);
|
||||||
|
_allAreMuted = allAreMuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::setCloudListSize(int size) {
|
||||||
|
if (_cloudListSize == size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_cloudListSize = size;
|
||||||
|
recomputeFullListSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const rpl::variable<int> &MainList::fullSize() const {
|
||||||
|
return _fullListSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainList::clear() {
|
void MainList::clear() {
|
||||||
|
const auto notifier = unreadStateChangeNotifier(true);
|
||||||
_all.clear();
|
_all.clear();
|
||||||
_unreadState = UnreadState();
|
_unreadState = UnreadState();
|
||||||
|
_cloudUnreadState = UnreadState();
|
||||||
|
_unreadState.known = true;
|
||||||
|
_cloudUnreadState.known = true;
|
||||||
|
_cloudListSize = 0;
|
||||||
|
recomputeFullListSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
RowsByLetter MainList::addEntry(const Key &key) {
|
||||||
|
const auto result = _all.addToEnd(key);
|
||||||
|
|
||||||
|
const auto unread = key.entry()->chatListUnreadState();
|
||||||
|
unreadEntryChanged(unread, true);
|
||||||
|
recomputeFullListSize();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::removeEntry(const Key &key) {
|
||||||
|
_all.del(key);
|
||||||
|
|
||||||
|
const auto unread = key.entry()->chatListUnreadState();
|
||||||
|
unreadEntryChanged(unread, false);
|
||||||
|
recomputeFullListSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::recomputeFullListSize() {
|
||||||
|
_fullListSize = std::max(_all.size(), loaded() ? 0 : _cloudListSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainList::unreadStateChanged(
|
void MainList::unreadStateChanged(
|
||||||
const UnreadState &wasState,
|
const UnreadState &wasState,
|
||||||
const UnreadState &nowState) {
|
const UnreadState &nowState) {
|
||||||
|
const auto updateCloudUnread = _cloudUnreadState.known && wasState.known;
|
||||||
|
const auto notify = loaded() || updateCloudUnread;
|
||||||
|
const auto notifier = unreadStateChangeNotifier(notify);
|
||||||
_unreadState += nowState - wasState;
|
_unreadState += nowState - wasState;
|
||||||
|
if (updateCloudUnread) {
|
||||||
|
Assert(nowState.known);
|
||||||
|
_cloudUnreadState += nowState - wasState;
|
||||||
|
finalizeCloudUnread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainList::unreadEntryChanged(
|
void MainList::unreadEntryChanged(
|
||||||
const Dialogs::UnreadState &state,
|
const Dialogs::UnreadState &state,
|
||||||
bool added) {
|
bool added) {
|
||||||
|
if (state.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto updateCloudUnread = _cloudUnreadState.known && state.known;
|
||||||
|
const auto notify = loaded() || updateCloudUnread;
|
||||||
|
const auto notifier = unreadStateChangeNotifier(notify);
|
||||||
if (added) {
|
if (added) {
|
||||||
_unreadState += state;
|
_unreadState += state;
|
||||||
} else {
|
} else {
|
||||||
_unreadState -= state;
|
_unreadState -= state;
|
||||||
}
|
}
|
||||||
|
if (updateCloudUnread) {
|
||||||
|
if (added) {
|
||||||
|
_cloudUnreadState += state;
|
||||||
|
} else {
|
||||||
|
_cloudUnreadState -= state;
|
||||||
|
}
|
||||||
|
finalizeCloudUnread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::updateCloudUnread(const MTPDdialogFolder &data) {
|
||||||
|
const auto notifier = unreadStateChangeNotifier(!loaded());
|
||||||
|
|
||||||
|
_cloudUnreadState.messages = data.vunread_muted_messages_count().v
|
||||||
|
+ data.vunread_unmuted_messages_count().v;
|
||||||
|
_cloudUnreadState.chats = data.vunread_muted_peers_count().v
|
||||||
|
+ data.vunread_unmuted_peers_count().v;
|
||||||
|
finalizeCloudUnread();
|
||||||
|
|
||||||
|
_cloudUnreadState.known = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainList::cloudUnreadKnown() const {
|
||||||
|
return _cloudUnreadState.known;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainList::finalizeCloudUnread() {
|
||||||
|
// Cloud state for archive folder always counts everything as muted.
|
||||||
|
_cloudUnreadState.messagesMuted = _cloudUnreadState.messages;
|
||||||
|
_cloudUnreadState.chatsMuted = _cloudUnreadState.chats;
|
||||||
|
|
||||||
|
// We don't know the real value of marked chats counts in cloud unread.
|
||||||
|
_cloudUnreadState.marksMuted = _cloudUnreadState.marks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnreadState MainList::unreadState() const {
|
UnreadState MainList::unreadState() const {
|
||||||
return _unreadState;
|
const auto useCloudState = _cloudUnreadState.known && !loaded();
|
||||||
|
auto result = useCloudState ? _cloudUnreadState : _unreadState;
|
||||||
|
|
||||||
|
// We don't know the real value of marked chats counts in cloud unread.
|
||||||
|
if (useCloudState) {
|
||||||
|
result.marks = _unreadState.marks;
|
||||||
|
result.marksMuted = _unreadState.marksMuted;
|
||||||
|
}
|
||||||
|
if (_allAreMuted) {
|
||||||
|
result.messagesMuted = result.messages;
|
||||||
|
result.chatsMuted = result.chats;
|
||||||
|
result.marksMuted = result.marks;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<UnreadState> MainList::unreadStateChanges() const {
|
||||||
|
return _unreadStateChanges.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<IndexedList*> MainList::indexed() {
|
not_null<IndexedList*> MainList::indexed() {
|
||||||
|
|
|
@ -19,28 +19,55 @@ public:
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
bool loaded() const;
|
bool loaded() const;
|
||||||
void setLoaded(bool loaded = true);
|
void setLoaded(bool loaded = true);
|
||||||
|
void setAllAreMuted(bool allAreMuted = true);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
RowsByLetter addEntry(const Key &key);
|
||||||
|
void removeEntry(const Key &key);
|
||||||
|
|
||||||
void unreadStateChanged(
|
void unreadStateChanged(
|
||||||
const UnreadState &wasState,
|
const UnreadState &wasState,
|
||||||
const UnreadState &nowState);
|
const UnreadState &nowState);
|
||||||
void unreadEntryChanged(
|
void unreadEntryChanged(
|
||||||
const Dialogs::UnreadState &state,
|
const Dialogs::UnreadState &state,
|
||||||
bool added);
|
bool added);
|
||||||
|
void updateCloudUnread(const MTPDdialogFolder &data);
|
||||||
|
[[nodiscard]] bool cloudUnreadKnown() const;
|
||||||
[[nodiscard]] UnreadState unreadState() const;
|
[[nodiscard]] UnreadState unreadState() const;
|
||||||
|
[[nodiscard]] rpl::producer<UnreadState> unreadStateChanges() const;
|
||||||
|
|
||||||
not_null<IndexedList*> indexed();
|
[[nodiscard]] not_null<IndexedList*> indexed();
|
||||||
not_null<const IndexedList*> indexed() const;
|
[[nodiscard]] not_null<const IndexedList*> indexed() const;
|
||||||
not_null<PinnedList*> pinned();
|
[[nodiscard]] not_null<PinnedList*> pinned();
|
||||||
not_null<const PinnedList*> pinned() const;
|
[[nodiscard]] not_null<const PinnedList*> pinned() const;
|
||||||
|
|
||||||
|
void setCloudListSize(int size);
|
||||||
|
[[nodiscard]] const rpl::variable<int> &fullSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void finalizeCloudUnread();
|
||||||
|
void recomputeFullListSize();
|
||||||
|
|
||||||
|
auto unreadStateChangeNotifier(bool notify) {
|
||||||
|
const auto wasState = notify ? unreadState() : UnreadState();
|
||||||
|
return gsl::finally([=] {
|
||||||
|
if (notify) {
|
||||||
|
_unreadStateChanges.fire_copy(wasState);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
FilterId _filterId = 0;
|
FilterId _filterId = 0;
|
||||||
IndexedList _all;
|
IndexedList _all;
|
||||||
PinnedList _pinned;
|
PinnedList _pinned;
|
||||||
UnreadState _unreadState;
|
UnreadState _unreadState;
|
||||||
|
UnreadState _cloudUnreadState;
|
||||||
|
rpl::event_stream<UnreadState> _unreadStateChanges;
|
||||||
|
rpl::variable<int> _fullListSize = 0;
|
||||||
|
int _cloudListSize = 0;
|
||||||
|
|
||||||
bool _loaded = false;
|
bool _loaded = false;
|
||||||
|
bool _allAreMuted = false;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ QString ComposeFolderListEntryText(not_null<Data::Folder*> folder) {
|
||||||
|
|
||||||
const auto count = std::max(
|
const auto count = std::max(
|
||||||
int(list.size()),
|
int(list.size()),
|
||||||
folder->chatsListSize());
|
folder->chatsList()->fullSize().current());
|
||||||
|
|
||||||
const auto throwAwayLastName = (list.size() > 1)
|
const auto throwAwayLastName = (list.size() > 1)
|
||||||
&& (count == list.size() + 1);
|
&& (count == list.size() + 1);
|
||||||
|
|
|
@ -280,7 +280,7 @@ Widget::Widget(
|
||||||
onSearchMore();
|
onSearchMore();
|
||||||
} else {
|
} else {
|
||||||
const auto folder = _inner->shownFolder();
|
const auto folder = _inner->shownFolder();
|
||||||
if (!folder || !folder->chatsListLoaded()) {
|
if (!folder || !folder->chatsList()->loaded()) {
|
||||||
session().api().requestDialogs(folder);
|
session().api().requestDialogs(folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1924,12 +1924,16 @@ void History::setFolderPointer(Data::Folder *folder) {
|
||||||
if (isPinnedDialog()) {
|
if (isPinnedDialog()) {
|
||||||
owner().setChatPinned(this, false);
|
owner().setChatPinned(this, false);
|
||||||
}
|
}
|
||||||
|
auto &filters = owner().chatsFilters();
|
||||||
const auto wasKnown = folderKnown();
|
const auto wasKnown = folderKnown();
|
||||||
const auto wasInList = inChatList();
|
const auto wasInList = inChatList();
|
||||||
if (wasInList) {
|
if (wasInList) {
|
||||||
removeFromChatList(0);
|
removeFromChatList(0, owner().chatsList(this->folder()));
|
||||||
for (const auto &filter : owner().chatsFilters().list()) {
|
for (const auto &filter : filters.list()) {
|
||||||
removeFromChatList(filter.id());
|
const auto id = filter.id();
|
||||||
|
if (inChatList(id)) {
|
||||||
|
removeFromChatList(id, filters.chatsList(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto was = _folder.value_or(nullptr);
|
const auto was = _folder.value_or(nullptr);
|
||||||
|
@ -1938,10 +1942,11 @@ void History::setFolderPointer(Data::Folder *folder) {
|
||||||
was->unregisterOne(this);
|
was->unregisterOne(this);
|
||||||
}
|
}
|
||||||
if (wasInList) {
|
if (wasInList) {
|
||||||
addToChatList(0);
|
addToChatList(0, owner().chatsList(folder));
|
||||||
for (const auto &filter : owner().chatsFilters().list()) {
|
for (const auto &filter : filters.list()) {
|
||||||
if (filter.contains(this)) {
|
if (filter.contains(this)) {
|
||||||
addToChatList(filter.id());
|
const auto id = filter.id();
|
||||||
|
addToChatList(id, filters.chatsList(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
owner().chatsListChanged(was);
|
owner().chatsListChanged(was);
|
||||||
|
|
Loading…
Reference in New Issue