diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp index c015de468..6e6fc98d4 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.cpp +++ b/Telegram/SourceFiles/data/data_chat_filters.cpp @@ -303,14 +303,16 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) { || (filter.always() != updated.always()) || (filter.never() != updated.never()); if (rulesChanged) { + const auto id = filter.id(); + const auto filterList = _owner->chatsFilters().chatsList(id); const auto feedHistory = [&](not_null history) { const auto now = updated.contains(history); const auto was = filter.contains(history); if (now != was) { if (now) { - history->addToChatList(filter.id()); + history->addToChatList(id, filterList); } else { - history->removeFromChatList(filter.id()); + history->removeFromChatList(id, filterList); } } }; @@ -322,8 +324,7 @@ bool ChatFilters::applyChange(ChatFilter &filter, ChatFilter &&updated) { } }; feedList(_owner->chatsList()); - const auto id = Data::Folder::kId; - if (const auto folder = _owner->folderLoaded(id)) { + if (const auto folder = _owner->folderLoaded(Data::Folder::kId)) { feedList(folder->chatsList()); } } else if (filter.title() == updated.title()) { diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index 41d3a5282..4cbcbb214 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -72,6 +72,22 @@ Folder::Folder(not_null owner, FolderId id) } } }, _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 { @@ -108,7 +124,7 @@ void Folder::indexNameParts() { void Folder::registerOne(not_null history) { if (_chatsList.indexed()->size() == 1) { updateChatListSortPosition(); - if (!_cloudUnread.known) { + if (!_chatsList.cloudUnreadKnown()) { owner().histories().requestDialogEntry(this); } } 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> &Folder::lastHistories() const { return _lastHistories; } @@ -333,7 +326,7 @@ TimeId Folder::adjustedChatListTimeId() const { } void Folder::applyDialog(const MTPDdialogFolder &data) { - updateCloudUnread(data); + _chatsList.updateCloudUnread(data); if (const auto peerId = peerFromMTP(data.vpeer())) { const auto history = owner().history(peerId); 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) { const auto folderId = data.vfolder_id().value_or_empty(); if (folderId != 0) { @@ -390,48 +350,6 @@ void Folder::applyPinnedUpdate(const MTPDupdateDialogPinned &data) { 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 //MessagePosition Folder::unreadPosition() const { // return _unreadPosition.current(); @@ -457,6 +375,10 @@ int Folder::chatListUnreadCount() const { : state.chats); } +Dialogs::UnreadState Folder::chatListUnreadState() const { + return _chatsList.unreadState(); +} + bool Folder::chatListUnreadMark() const { return false; // #feed unread mark } diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h index f1898f522..cba736f97 100644 --- a/Telegram/SourceFiles/data/data_folder.h +++ b/Telegram/SourceFiles/data/data_folder.h @@ -45,16 +45,6 @@ public: //MessagePosition unreadPosition() const; // #feed //rpl::producer 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; int fixedOnTopIndex() const override; @@ -85,11 +75,6 @@ public: const style::color &overrideBg, const style::color &overrideFg) const; - bool chatsListLoaded() const; - void setChatsListLoaded(bool loaded = true); - void setCloudChatsListSize(int size); - - int chatsListSize() const; const std::vector> &lastHistories() const; uint32 chatListViewVersion() const; @@ -99,7 +84,6 @@ private: void computeChatListMessage(); void reorderLastHistories(); - void finalizeCloudUnread(); void paintUserpic( Painter &p, @@ -116,8 +100,6 @@ private: base::flat_set _nameWords; base::flat_set _nameFirstLetters; - Dialogs::UnreadState _cloudUnread; - int _cloudChatsListSize = 0; std::vector> _lastHistories; HistoryItem *_chatListMessage = nullptr; uint32 _chatListViewVersion = 0; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 1f134b8e0..b36cb50cc 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -214,6 +214,11 @@ Session::Session(not_null session) setupChannelLeavingViewer(); setupPeerNameViewer(); setupUserIsContactViewer(); + + _chatsList.unreadStateChanges( + ) | rpl::start_with_next([] { + Notify::unreadCounterUpdated(); + }, _lifetime); } void Session::clear() { @@ -833,7 +838,7 @@ void Session::chatsListChanged(Data::Folder *folder) { void Session::chatsListDone(Data::Folder *folder) { if (folder) { - folder->setChatsListLoaded(); + folder->chatsList()->setLoaded(); } else { _chatsList.setLoaded(); } @@ -1506,7 +1511,7 @@ void Session::applyDialogs( }); } if (requestFolder && count) { - requestFolder->setCloudChatsListSize(*count); + requestFolder->chatsList()->setCloudListSize(*count); } } @@ -2016,35 +2021,6 @@ bool Session::computeUnreadBadgeMuted( : (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 item, crl::time delay) { _selfDestructItems.push_back(item->fullId()); if (!_selfDestructTimer.isActive() @@ -3347,33 +3323,42 @@ auto Session::refreshChatListEntry( Dialogs::Key key, FilterId filterIdForResult) -> RefreshChatListEntryResult { + Expects(key.entry()->folderKnown()); + using namespace Dialogs; const auto entry = key.entry(); const auto history = key.history(); + const auto mainList = chatsList(entry->folder()); auto mainListResult = RefreshChatListEntryResult(); mainListResult.changed = !entry->inChatList(); if (mainListResult.changed) { - const auto mainRow = entry->addToChatList(0); + const auto mainRow = entry->addToChatList(0, mainList); _contactsNoChatsList.del(key, mainRow); } else { - mainListResult.moved = entry->adjustByPosInChatList(0); + mainListResult.moved = entry->adjustByPosInChatList(0, mainList); } auto result = filterIdForResult ? RefreshChatListEntryResult() : mainListResult; + if (!history) { + return result; + } for (const auto &filter : _chatsFilters->list()) { const auto id = filter.id(); + const auto filterList = chatsFilters().chatsList(id); auto filterResult = RefreshChatListEntryResult(); - if (history && filter.contains(history)) { + if (filter.contains(history)) { filterResult.changed = !entry->inChatList(id); if (filterResult.changed) { - entry->addToChatList(id); + entry->addToChatList(id, filterList); } else { - filterResult.moved = entry->adjustByPosInChatList(id); + filterResult.moved = entry->adjustByPosInChatList( + id, + filterList); } } else if (entry->inChatList(id)) { - entry->removeFromChatList(id); + entry->removeFromChatList(id, filterList); filterResult.changed = true; } if (id == filterIdForResult) { @@ -3387,9 +3372,17 @@ void Session::removeChatListEntry(Dialogs::Key key) { using namespace Dialogs; 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()) { - entry->removeFromChatList(filter.id()); + const auto id = filter.id(); + if (entry->inChatList(id)) { + entry->removeFromChatList(id, chatsFilters().chatsList(id)); + } } if (_contactsList.contains(key)) { if (!_contactsNoChatsList.contains(key)) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index f4ac5d7b8..8ff99c45e 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -449,11 +449,6 @@ public: bool unreadBadgeMutedIgnoreOne(const Dialogs::Key &key) 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 item, crl::time delay); [[nodiscard]] not_null photo(PhotoId id); diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp index 05cb676ab..c94c07814 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp @@ -112,7 +112,15 @@ void Entry::updateChatListExistence() { } 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) { @@ -154,11 +162,13 @@ Row *Entry::maybeMainChatListLink(FilterId filterId) const { return links ? links->main.get() : nullptr; } -PositionChange Entry::adjustByPosInChatList(FilterId filterId) { +PositionChange Entry::adjustByPosInChatList( + FilterId filterId, + not_null list) { const auto links = chatListLinks(filterId); Assert(links != nullptr); const auto from = links->main->pos(); - myChatsList(filterId)->adjustByDate(*links); + list->indexed()->adjustByDate(*links); const auto to = links->main->pos(); return { from, to }; } @@ -175,30 +185,27 @@ int Entry::posInChatList(FilterId filterId) const { return mainChatListLink(filterId)->pos(); } -not_null Entry::addToChatList(FilterId filterId) { +not_null Entry::addToChatList( + FilterId filterId, + not_null list) { if (const auto main = maybeMainChatListLink(filterId)) { return main; } - const auto result = _chatListLinks.emplace( + return _chatListLinks.emplace( filterId, - myChatsList(filterId)->addToEnd(_key) + list->addEntry(_key) ).first->second.main; - if (!filterId) { - owner().unreadEntryChanged(_key, true); - } - return result; } -void Entry::removeFromChatList(FilterId filterId) { +void Entry::removeFromChatList( + FilterId filterId, + not_null list) { const auto i = _chatListLinks.find(filterId); if (i == end(_chatListLinks)) { return; } - myChatsList(filterId)->del(_key); _chatListLinks.erase(i); - if (!filterId) { - owner().unreadEntryChanged(_key, false); - } + list->removeEntry(_key); } void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) { @@ -230,10 +237,4 @@ void Entry::updateChatListEntry() const { } } -not_null Entry::myChatsList(FilterId filterId) const { - return filterId - ? owner().chatsFilters().chatsList(filterId)->indexed() - : owner().chatsList(folder())->indexed(); -} - } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index 05be48d33..eb0bfe194 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -24,6 +24,7 @@ namespace Dialogs { class Row; class IndexedList; +class MainList; struct RowsByLetter { not_null main; @@ -97,13 +98,19 @@ public: [[nodiscard]] Data::Session &owner() const; [[nodiscard]] Main::Session &session() const; - PositionChange adjustByPosInChatList(FilterId filterId); + PositionChange adjustByPosInChatList( + FilterId filterId, + not_null list); [[nodiscard]] bool inChatList(FilterId filterId = 0) const { return _chatListLinks.contains(filterId); } [[nodiscard]] int posInChatList(FilterId filterId) const; - not_null addToChatList(FilterId filterId); - void removeFromChatList(FilterId filterId); + not_null addToChatList( + FilterId filterId, + not_null list); + void removeFromChatList( + FilterId filterId, + not_null list); void removeChatListEntryByLetter(FilterId filterId, QChar letter); void addChatListEntryByLetter( FilterId filterId, @@ -176,6 +183,7 @@ public: mutable Ui::Text::String lastItemTextCache; protected: + void notifyUnreadStateChange(const UnreadState &wasState); auto unreadStateChangeNotifier(bool required) { const auto notify = required && inChatList(); const auto wasState = notify ? chatListUnreadState() : UnreadState(); @@ -189,16 +197,12 @@ protected: private: virtual void changedChatListPinHook(); - void notifyUnreadStateChange(const UnreadState &wasState); - void setChatListExistence(bool exists); RowsByLetter *chatListLinks(FilterId filterId); const RowsByLetter *chatListLinks(FilterId filterId) const; not_null mainChatListLink(FilterId filterId) const; Row *maybeMainChatListLink(FilterId filterId) const; - not_null myChatsList(FilterId filterId) const; - not_null _owner; Dialogs::Key _key; base::flat_map _chatListLinks; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index ee702a6f3..5fe6aa593 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1728,7 +1728,9 @@ void InnerWidget::fillSupportSearchMenu(not_null menu) { void InnerWidget::fillArchiveSearchMenu(not_null menu) { const auto folder = session().data().folderLoaded(Data::Folder::kId); - if (!folder || !folder->chatsListSize() || _searchInChat) { + if (!folder + || !folder->chatsList()->fullSize().current() + || _searchInChat) { return; } const auto skip = session().settings().skipArchiveInSearch(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp index c6f01db27..f1e54e957 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp @@ -42,32 +42,149 @@ bool MainList::loaded() const { } void MainList::setLoaded(bool loaded) { + if (_loaded == loaded) { + return; + } + const auto notifier = unreadStateChangeNotifier(true); _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 &MainList::fullSize() const { + return _fullListSize; } void MainList::clear() { + const auto notifier = unreadStateChangeNotifier(true); _all.clear(); _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( const UnreadState &wasState, const UnreadState &nowState) { + const auto updateCloudUnread = _cloudUnreadState.known && wasState.known; + const auto notify = loaded() || updateCloudUnread; + const auto notifier = unreadStateChangeNotifier(notify); _unreadState += nowState - wasState; + if (updateCloudUnread) { + Assert(nowState.known); + _cloudUnreadState += nowState - wasState; + finalizeCloudUnread(); + } } void MainList::unreadEntryChanged( const Dialogs::UnreadState &state, 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) { _unreadState += state; } else { _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 { - 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 MainList::unreadStateChanges() const { + return _unreadStateChanges.events(); } not_null MainList::indexed() { diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.h b/Telegram/SourceFiles/dialogs/dialogs_main_list.h index 5bc69ba0e..c9ac27480 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_main_list.h +++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.h @@ -19,28 +19,55 @@ public: bool empty() const; bool loaded() const; void setLoaded(bool loaded = true); + void setAllAreMuted(bool allAreMuted = true); void clear(); + RowsByLetter addEntry(const Key &key); + void removeEntry(const Key &key); + void unreadStateChanged( const UnreadState &wasState, const UnreadState &nowState); void unreadEntryChanged( const Dialogs::UnreadState &state, bool added); + void updateCloudUnread(const MTPDdialogFolder &data); + [[nodiscard]] bool cloudUnreadKnown() const; [[nodiscard]] UnreadState unreadState() const; + [[nodiscard]] rpl::producer unreadStateChanges() const; - not_null indexed(); - not_null indexed() const; - not_null pinned(); - not_null pinned() const; + [[nodiscard]] not_null indexed(); + [[nodiscard]] not_null indexed() const; + [[nodiscard]] not_null pinned(); + [[nodiscard]] not_null pinned() const; + + void setCloudListSize(int size); + [[nodiscard]] const rpl::variable &fullSize() const; 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; IndexedList _all; PinnedList _pinned; UnreadState _unreadState; + UnreadState _cloudUnreadState; + rpl::event_stream _unreadStateChanges; + rpl::variable _fullListSize = 0; + int _cloudListSize = 0; bool _loaded = false; + bool _allAreMuted = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 1953ad5db..00b31be44 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -28,7 +28,7 @@ QString ComposeFolderListEntryText(not_null folder) { const auto count = std::max( int(list.size()), - folder->chatsListSize()); + folder->chatsList()->fullSize().current()); const auto throwAwayLastName = (list.size() > 1) && (count == list.size() + 1); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 658bcd857..406075ee2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -280,7 +280,7 @@ Widget::Widget( onSearchMore(); } else { const auto folder = _inner->shownFolder(); - if (!folder || !folder->chatsListLoaded()) { + if (!folder || !folder->chatsList()->loaded()) { session().api().requestDialogs(folder); } } diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 96148c10d..0d9680c30 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1924,12 +1924,16 @@ void History::setFolderPointer(Data::Folder *folder) { if (isPinnedDialog()) { owner().setChatPinned(this, false); } + auto &filters = owner().chatsFilters(); const auto wasKnown = folderKnown(); const auto wasInList = inChatList(); if (wasInList) { - removeFromChatList(0); - for (const auto &filter : owner().chatsFilters().list()) { - removeFromChatList(filter.id()); + removeFromChatList(0, owner().chatsList(this->folder())); + for (const auto &filter : filters.list()) { + const auto id = filter.id(); + if (inChatList(id)) { + removeFromChatList(id, filters.chatsList(id)); + } } } const auto was = _folder.value_or(nullptr); @@ -1938,10 +1942,11 @@ void History::setFolderPointer(Data::Folder *folder) { was->unregisterOne(this); } if (wasInList) { - addToChatList(0); - for (const auto &filter : owner().chatsFilters().list()) { + addToChatList(0, owner().chatsList(folder)); + for (const auto &filter : filters.list()) { if (filter.contains(this)) { - addToChatList(filter.id()); + const auto id = filter.id(); + addToChatList(id, filters.chatsList(id)); } } owner().chatsListChanged(was);