From 4910a60499547316c0391a3f78069155a45efb55 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Oct 2022 12:57:12 +0400 Subject: [PATCH] Track mentions / reactions together with unread. --- Telegram/SourceFiles/api/api_updates.cpp | 6 +- .../SourceFiles/data/data_chat_filters.cpp | 10 +- Telegram/SourceFiles/data/data_folder.cpp | 25 +- Telegram/SourceFiles/data/data_folder.h | 4 +- .../SourceFiles/data/data_forum_topic.cpp | 95 +++--- Telegram/SourceFiles/data/data_forum_topic.h | 13 +- Telegram/SourceFiles/data/data_thread.cpp | 2 +- Telegram/SourceFiles/data/data_thread.h | 6 +- .../SourceFiles/dialogs/dialogs_entry.cpp | 51 ++- Telegram/SourceFiles/dialogs/dialogs_entry.h | 85 +++-- .../dialogs/dialogs_inner_widget.cpp | 8 +- .../SourceFiles/dialogs/dialogs_main_list.cpp | 9 +- .../SourceFiles/dialogs/dialogs_main_list.h | 8 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 4 +- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 317 +++++------------- Telegram/SourceFiles/history/history.cpp | 169 +++++----- Telegram/SourceFiles/history/history.h | 13 +- .../history/history_unread_things.cpp | 9 +- .../SourceFiles/history/history_widget.cpp | 26 +- .../touchbar/items/mac_pinned_chats_item.mm | 12 +- .../SourceFiles/window/window_main_menu.cpp | 8 +- .../SourceFiles/window/window_peer_menu.cpp | 5 +- 22 files changed, 407 insertions(+), 478 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 30b2430c6..51fdd65d3 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -1711,11 +1711,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { if (const auto history = session().data().historyLoaded(id)) { history->setUnreadMark(data.is_unread()); } - }, [&](const MTPDdialogPeerFolder &dialog) { - //const auto id = dialog.vfolder_id().v; // #TODO archive - //if (const auto folder = session().data().folderLoaded(id)) { - // folder->setUnreadMark(data.is_unread()); - //} + }, [](const MTPDdialogPeerFolder &dialog) { }); } break; diff --git a/Telegram/SourceFiles/data/data_chat_filters.cpp b/Telegram/SourceFiles/data/data_chat_filters.cpp index 06a23030b..d7472837a 100644 --- a/Telegram/SourceFiles/data/data_chat_filters.cpp +++ b/Telegram/SourceFiles/data/data_chat_filters.cpp @@ -204,17 +204,19 @@ bool ChatFilter::contains(not_null history) const { if (_never.contains(history)) { return false; } + const auto state = (_flags & (Flag::NoMuted | Flag::NoRead)) + ? history->chatListBadgesState() + : Dialogs::BadgesState(); return false || ((_flags & flag) && (!(_flags & Flag::NoMuted) || !history->muted() - || (history->unreadMentions().has() + || (state.mention && history->folderKnown() && !history->folder())) && (!(_flags & Flag::NoRead) - || history->chatListUnreadCount() - || history->unreadMark() - || history->unreadMentions().has() + || state.unread + || state.mention || history->fakeUnreadWhileOpened()) && (!(_flags & Flag::NoArchived) || (history->folderKnown() && !history->folder()))) diff --git a/Telegram/SourceFiles/data/data_folder.cpp b/Telegram/SourceFiles/data/data_folder.cpp index cf3db1cbc..7c7e16a6d 100644 --- a/Telegram/SourceFiles/data/data_folder.cpp +++ b/Telegram/SourceFiles/data/data_folder.cpp @@ -62,7 +62,6 @@ Folder::Folder(not_null owner, FolderId id) }) | rpl::start_with_next([=](const Dialogs::UnreadState &old) { ++_chatListViewVersion; notifyUnreadStateChange(old); - updateChatListEntryPostponed(); }, _lifetime); _chatsList.fullSize().changes( @@ -328,24 +327,20 @@ bool Folder::shouldBeInChatList() const { return !_chatsList.empty(); } -int Folder::chatListUnreadCount() const { - const auto state = chatListUnreadState(); - return state.marks - + (Core::App().settings().countUnreadMessages() - ? state.messages - : state.chats); -} - Dialogs::UnreadState Folder::chatListUnreadState() const { return _chatsList.unreadState(); } -bool Folder::chatListUnreadMark() const { - return false; -} - -bool Folder::chatListMutedBadge() const { - return true; +Dialogs::BadgesState Folder::chatListBadgesState() const { + auto result = Dialogs::BadgesForUnread( + chatListUnreadState(), + Dialogs::CountInBadge::Chats, + Dialogs::IncludeInBadge::All); + result.unreadMuted = result.mentionMuted = result.reactionMuted = true; + if (result.unread && !result.unreadCounter) { + result.unreadCounter = 1; + } + return result; } HistoryItem *Folder::chatListMessage() const { diff --git a/Telegram/SourceFiles/data/data_folder.h b/Telegram/SourceFiles/data/data_folder.h index 986fa9368..438985122 100644 --- a/Telegram/SourceFiles/data/data_folder.h +++ b/Telegram/SourceFiles/data/data_folder.h @@ -44,10 +44,8 @@ public: int fixedOnTopIndex() const override; bool shouldBeInChatList() const override; - int chatListUnreadCount() const override; - bool chatListUnreadMark() const override; - bool chatListMutedBadge() const override; Dialogs::UnreadState chatListUnreadState() const override; + Dialogs::BadgesState chatListBadgesState() const override; HistoryItem *chatListMessage() const override; bool chatListMessageKnown() const override; void requestChatListMessage() override; diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 73f41b451..d18a709b7 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -155,7 +155,6 @@ ForumTopic::ForumTopic(not_null forum, MsgId rootId) _replies->unreadCountValue( ) | rpl::combine_previous( ) | rpl::filter([=] { - session().changes().topicUpdated(this, UpdateFlag::UnreadView); return inChatList(); }) | rpl::start_with_next([=]( std::optional previous, @@ -602,87 +601,52 @@ bool ForumTopic::isServerSideUnread( return _replies->isServerSideUnread(item); } -int ForumTopic::unreadCount() const { - return _replies->unreadCountCurrent(); -} - -int ForumTopic::unreadCountForBadge() const { - const auto result = unreadCount(); - return (!result && unreadMark()) ? 1 : result; -} - void ForumTopic::setMuted(bool muted) { if (this->muted() == muted) { return; } - const auto refresher = gsl::finally([&] { - if (inChatList()) { - updateChatListEntry(); - } - session().changes().topicUpdated( - this, - Data::TopicUpdate::Flag::Notifications); - }); - const auto notify = (unreadCountForBadge() > 0); + const auto state = chatListBadgesState(); + const auto notify = state.unread || state.reaction; const auto notifier = unreadStateChangeNotifier(notify); Thread::setMuted(muted); -} - -bool ForumTopic::unreadCountKnown() const { - return _replies->unreadCountKnown(); -} - -void ForumTopic::setUnreadMark(bool unread) { - if (unreadMark() == unread) { - return; - } - const auto noUnreadMessages = !unreadCount(); - const auto refresher = gsl::finally([&] { - if (inChatList() && noUnreadMessages) { - updateChatListEntry(); - } - session().changes().topicUpdated(this, UpdateFlag::UnreadView); - }); - const auto notifier = unreadStateChangeNotifier(noUnreadMessages); - Thread::setUnreadMark(unread); + session().changes().topicUpdated( + this, + Data::TopicUpdate::Flag::Notifications); } not_null ForumTopic::sendActionPainter() { return _sendActionPainter.get(); } -int ForumTopic::chatListUnreadCount() const { - return unreadCount(); +Dialogs::UnreadState ForumTopic::chatListUnreadState() const { + return unreadStateFor( + _replies->unreadCountCurrent(), + _replies->unreadCountKnown()); } -Dialogs::UnreadState ForumTopic::chatListUnreadState() const { - return unreadStateFor(unreadCount(), unreadCountKnown()); +Dialogs::BadgesState ForumTopic::chatListBadgesState() const { + return Dialogs::BadgesForUnread( + chatListUnreadState(), + Dialogs::CountInBadge::Messages, + Dialogs::IncludeInBadge::All); } Dialogs::UnreadState ForumTopic::unreadStateFor( int count, bool known) const { auto result = Dialogs::UnreadState(); - const auto mark = !count && unreadMark(); const auto muted = this->muted(); result.messages = count; - result.messagesMuted = muted ? count : 0; result.chats = count ? 1 : 0; - result.chatsMuted = (count && muted) ? 1 : 0; - result.marks = mark ? 1 : 0; - result.marksMuted = (mark && muted) ? 1 : 0; + result.mentions = unreadMentions().has() ? 1 : 0; + result.reactions = unreadReactions().has() ? 1 : 0; + result.messagesMuted = muted ? result.messages : 0; + result.chatsMuted = muted ? result.chats : 0; + result.reactionsMuted = muted ? result.reactions : 0; result.known = known; return result; } -bool ForumTopic::chatListUnreadMark() const { - return false; -} - -bool ForumTopic::chatListMutedBadge() const { - return muted(); -} - HistoryItem *ForumTopic::chatListMessage() const { return _lastMessage.value_or(nullptr); } @@ -703,6 +667,27 @@ const base::flat_set &ForumTopic::chatListFirstLetters() const { return _titleFirstLetters; } +void ForumTopic::hasUnreadMentionChanged(bool has) { + auto was = chatListUnreadState(); + if (has) { + was.mentions = 0; + } else { + was.mentions = 1; + } + notifyUnreadStateChange(was); +} + +void ForumTopic::hasUnreadReactionChanged(bool has) { + auto was = chatListUnreadState(); + if (has) { + was.reactions = was.reactionsMuted = 0; + } else { + was.reactions = 1; + was.reactionsMuted = muted() ? was.reactions : 0; + } + notifyUnreadStateChange(was); +} + const QString &ForumTopic::chatListNameSortKey() const { static const auto empty = QString(); return empty; diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h index 9bebe2eef..2f23842f8 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.h +++ b/Telegram/SourceFiles/data/data_forum_topic.h @@ -81,10 +81,8 @@ public: int fixedOnTopIndex() const override; bool shouldBeInChatList() const override; - int chatListUnreadCount() const override; - bool chatListUnreadMark() const override; - bool chatListMutedBadge() const override; Dialogs::UnreadState chatListUnreadState() const override; + Dialogs::BadgesState chatListBadgesState() const override; HistoryItem *chatListMessage() const override; bool chatListMessageKnown() const override; void requestChatListMessage() override; @@ -93,6 +91,9 @@ public: const base::flat_set &chatListNameWords() const override; const base::flat_set &chatListFirstLetters() const override; + void hasUnreadMentionChanged(bool has) override; + void hasUnreadReactionChanged(bool has) override; + [[nodiscard]] HistoryItem *lastMessage() const; [[nodiscard]] HistoryItem *lastServerMessage() const; [[nodiscard]] bool lastMessageKnown() const; @@ -125,13 +126,7 @@ public: [[nodiscard]] bool isServerSideUnread( not_null item) const override; - [[nodiscard]] int unreadCount() const; - [[nodiscard]] bool unreadCountKnown() const; - - [[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0. - void setMuted(bool muted) override; - void setUnreadMark(bool unread) override; [[nodiscard]] auto sendActionPainter() ->not_null override; diff --git a/Telegram/SourceFiles/data/data_thread.cpp b/Telegram/SourceFiles/data/data_thread.cpp index 7c42a92b9..9efa9db9d 100644 --- a/Telegram/SourceFiles/data/data_thread.cpp +++ b/Telegram/SourceFiles/data/data_thread.cpp @@ -144,7 +144,7 @@ void Thread::setMuted(bool muted) { } } -void Thread::setUnreadMark(bool unread) { +void Thread::setUnreadMarkFlag(bool unread) { if (unread) { _flags |= Flag::UnreadMark; } else { diff --git a/Telegram/SourceFiles/data/data_thread.h b/Telegram/SourceFiles/data/data_thread.h index 58df8b7f4..9f3203bc2 100644 --- a/Telegram/SourceFiles/data/data_thread.h +++ b/Telegram/SourceFiles/data/data_thread.h @@ -71,6 +71,8 @@ public: [[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const; [[nodiscard]] HistoryUnreadThings::Proxy unreadReactions(); [[nodiscard]] HistoryUnreadThings::ConstProxy unreadReactions() const; + virtual void hasUnreadMentionChanged(bool has) = 0; + virtual void hasUnreadReactionChanged(bool has) = 0; void removeNotification(not_null item); void clearNotifications(); @@ -90,7 +92,6 @@ public: [[nodiscard]] bool unreadMark() const { return (_flags & Flag::UnreadMark); } - virtual void setUnreadMark(bool unread); [[nodiscard]] virtual bool isServerSideUnread( not_null item) const = 0; @@ -108,6 +109,9 @@ public: [[nodiscard]] virtual auto sendActionPainter() -> not_null = 0; +protected: + void setUnreadMarkFlag(bool unread); + private: enum class Flag : uchar { UnreadMark = (1 << 0), diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp index 4155d3f9c..45bcea5a3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.cpp @@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_folder.h" #include "data/data_forum_topic.h" #include "data/data_chat_filters.h" +#include "core/application.h" +#include "core/core_settings.h" #include "mainwidget.h" #include "main/main_session.h" #include "main/main_session_settings.h" @@ -44,6 +46,37 @@ uint64 PinnedDialogPos(int pinnedIndex) { } // namespace +BadgesState BadgesForUnread( + const UnreadState &state, + CountInBadge count, + IncludeInBadge include) { + const auto countMessages = (count == CountInBadge::Messages) + || ((count == CountInBadge::Default) + && Core::App().settings().countUnreadMessages()); + const auto counterFull = state.marks + + (countMessages ? state.messages : state.chats); + const auto counterMuted = state.marksMuted + + (countMessages ? state.messagesMuted : state.chatsMuted); + const auto unreadMuted = (counterFull <= counterMuted); + + const auto includeMuted = (include == IncludeInBadge::All) + || (include == IncludeInBadge::UnmutedOrAll && unreadMuted) + || ((include == IncludeInBadge::Default) + && Core::App().settings().includeMutedCounter()); + + const auto marks = state.marks - (includeMuted ? 0 : state.marksMuted); + const auto counter = counterFull - (includeMuted ? 0 : counterMuted); + const auto mark = (counter == 1) && (marks == 1); + return { + .unreadCounter = mark ? 0 : counter, + .unread = (counter > 0), + .unreadMuted = includeMuted && (counter <= counterMuted), + .mention = (state.mentions > 0), + .reaction = (state.reactions > 0), + .reactionMuted = (state.reactions <= state.reactionsMuted), + }; +} + Entry::Entry(not_null owner, Type type) : _owner(owner) , _flags((type == Type::History) @@ -181,8 +214,24 @@ void Entry::notifyUnreadStateChange(const UnreadState &wasState) { owner().chatsListFor(this)->unreadStateChanged(wasState, nowState); auto &filters = owner().chatsFilters(); for (const auto &[filterId, links] : _chatListLinks) { - filters.chatsList(filterId)->unreadStateChanged(wasState, nowState); + if (filterId) { + filters.chatsList(filterId)->unreadStateChanged( + wasState, + nowState); + } } + if (const auto history = asHistory()) { + session().changes().historyUpdated( + history, + Data::HistoryUpdate::Flag::UnreadView); + const auto isForFilters = [](UnreadState state) { + return state.messages || state.marks || state.mentions; + }; + if (isForFilters(wasState) != isForFilters(nowState)) { + owner().chatsFilters().refreshHistory(history); + } + } + updateChatListEntryPostponed(); } const Ui::Text::String &Entry::chatListNameText() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_entry.h b/Telegram/SourceFiles/dialogs/dialogs_entry.h index 8541b9037..8c9a85530 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_entry.h +++ b/Telegram/SourceFiles/dialogs/dialogs_entry.h @@ -64,6 +64,9 @@ struct UnreadState { int chatsMuted = 0; int marks = 0; int marksMuted = 0; + int reactions = 0; + int reactionsMuted = 0; + int mentions = 0; bool known = false; UnreadState &operator+=(const UnreadState &other) { @@ -73,6 +76,9 @@ struct UnreadState { chatsMuted += other.chatsMuted; marks += other.marks; marksMuted += other.marksMuted; + reactions += other.reactions; + reactionsMuted += other.reactionsMuted; + mentions += other.mentions; return *this; } UnreadState &operator-=(const UnreadState &other) { @@ -82,12 +88,11 @@ struct UnreadState { chatsMuted -= other.chatsMuted; marks -= other.marks; marksMuted -= other.marksMuted; + reactions -= other.reactions; + reactionsMuted -= other.reactionsMuted; + mentions -= other.mentions; return *this; } - - bool empty() const { - return !messages && !chats && !marks; - } }; inline UnreadState operator+(const UnreadState &a, const UnreadState &b) { @@ -102,6 +107,42 @@ inline UnreadState operator-(const UnreadState &a, const UnreadState &b) { return result; } +struct BadgesState { + int unreadCounter = 0; + bool unread : 1 = false; + bool unreadMuted : 1 = false; + bool mention : 1 = false; + bool mentionMuted : 1 = false; + bool reaction : 1 = false; + bool reactionMuted : 1 = false; + + friend inline constexpr auto operator<=>( + BadgesState, + BadgesState) = default; + + [[nodiscard]] bool empty() const { + return !unread && !mention && !reaction; + } +}; + +enum class CountInBadge : uchar { + Default, + Chats, + Messages, +}; + +enum class IncludeInBadge : uchar { + Default, + Unmuted, + All, + UnmutedOrAll, +}; + +[[nodiscard]] BadgesState BadgesForUnread( + const UnreadState &state, + CountInBadge count = CountInBadge::Default, + IncludeInBadge include = IncludeInBadge::Default); + class Entry : public base::has_weak_ptr { public: enum class Type : uchar { @@ -167,10 +208,8 @@ public: static constexpr auto kTopPromotionFixOnTopIndex = 2; virtual bool shouldBeInChatList() const = 0; - virtual int chatListUnreadCount() const = 0; - virtual bool chatListUnreadMark() const = 0; - virtual bool chatListMutedBadge() const = 0; virtual UnreadState chatListUnreadState() const = 0; + virtual BadgesState chatListBadgesState() const = 0; virtual HistoryItem *chatListMessage() const = 0; virtual bool chatListMessageKnown() const = 0; virtual void requestChatListMessage() = 0; @@ -197,21 +236,13 @@ public: } [[nodiscard]] const Ui::Text::String &chatListNameText() const; - [[nodiscard]] Ui::PeerBadge &chatListBadge() const { - return _chatListBadge; + [[nodiscard]] Ui::PeerBadge &chatListPeerBadge() const { + return _chatListPeerBadge; } protected: void notifyUnreadStateChange(const UnreadState &wasState); - auto unreadStateChangeNotifier(bool required) { - const auto notify = required && inChatList(); - const auto wasState = notify ? chatListUnreadState() : UnreadState(); - return gsl::finally([=] { - if (notify) { - notifyUnreadStateChange(wasState); - } - }); - } + auto unreadStateChangeNotifier(bool required); [[nodiscard]] int lookupPinnedIndex(FilterId filterId) const; @@ -220,6 +251,7 @@ private: IsThread = (1 << 0), IsHistory = (1 << 1), UpdatePostponed = (1 << 2), + InUnreadChangeBlock = (1 << 3), }; friend inline constexpr bool is_flag_type(Flag) { return true; } using Flags = base::flags; @@ -239,7 +271,7 @@ private: uint64 _sortKeyInChatList = 0; uint64 _sortKeyByDate = 0; base::flat_map _pinnedIndex; - mutable Ui::PeerBadge _chatListBadge; + mutable Ui::PeerBadge _chatListPeerBadge; mutable Ui::Text::String _chatListNameText; mutable int _chatListNameVersion = 0; TimeId _timeId = 0; @@ -247,4 +279,19 @@ private: }; +auto Entry::unreadStateChangeNotifier(bool required) { + Expects(!(_flags & Flag::InUnreadChangeBlock)); + + _flags |= Flag::InUnreadChangeBlock; + const auto notify = required && inChatList(); + const auto wasState = notify ? chatListUnreadState() : UnreadState(); + return gsl::finally([=] { + _flags &= ~Flag::InUnreadChangeBlock; + if (notify) { + Assert(inChatList()); + notifyUnreadStateChange(wasState); + } + }); +} + } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index f4a9aa577..08b613c5d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -799,7 +799,7 @@ void InnerWidget::paintCollapsedRow( Expects(row->folder != nullptr); const auto text = row->folder->chatListName(); - const auto unread = row->folder->chatListUnreadCount(); + const auto unread = row->folder->chatListBadgesState().unreadCounter; Ui::PaintCollapsedRow(p, row->row, row->folder, text, unread, { .st = _st, .width = width(), @@ -3435,8 +3435,7 @@ void InnerWidget::setupShortcuts() { request->check(Command::ReadChat) && request->handle([=] { const auto history = _selected ? _selected->history() : nullptr; if (history) { - if ((history->chatListUnreadCount() > 0) - || history->chatListUnreadMark()) { + if (history->chatListBadgesState().unread) { session().data().histories().readInbox(history); } return true; @@ -3470,8 +3469,7 @@ RowDescriptor InnerWidget::computeJump( const auto needSkip = [&] { return (result.key.folder() != nullptr) || (session().supportMode() - && !result.key.entry()->chatListUnreadCount() - && !result.key.entry()->chatListUnreadMark()); + && !result.key.entry()->chatListBadgesState().unread); }; while (needSkip()) { const auto next = down diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp index 6ce9ef020..f4da53ab3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.cpp @@ -8,7 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_main_list.h" #include "data/data_changes.h" +#include "data/data_session.h" +#include "data/data_chat_filters.h" #include "main/main_session.h" +#include "history/history_unread_things.h" #include "history/history.h" namespace Dialogs { @@ -126,7 +129,11 @@ void MainList::unreadStateChanged( void MainList::unreadEntryChanged( const Dialogs::UnreadState &state, bool added) { - if (state.empty()) { + if (!state.messages + && !state.chats + && !state.marks + && !state.mentions + && !state.reactions) { return; } const auto updateCloudUnread = _cloudUnreadState.known && state.known; diff --git a/Telegram/SourceFiles/dialogs/dialogs_main_list.h b/Telegram/SourceFiles/dialogs/dialogs_main_list.h index c9aef1edf..ef0c739b3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_main_list.h +++ b/Telegram/SourceFiles/dialogs/dialogs_main_list.h @@ -14,6 +14,10 @@ namespace Main { class Session; } // namespace Main +namespace Data { +class Thread; +} // namespace Data + namespace Dialogs { class MainList final { @@ -35,9 +39,7 @@ public: void unreadStateChanged( const UnreadState &wasState, const UnreadState &nowState); - void unreadEntryChanged( - const Dialogs::UnreadState &state, - bool added); + void unreadEntryChanged(const UnreadState &state, bool added); void updateCloudUnread(const MTPDdialogFolder &data); [[nodiscard]] bool cloudUnreadKnown() const; [[nodiscard]] UnreadState unreadState() const; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 43ee090ed..dd6da06d6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -47,12 +47,12 @@ namespace { const auto name = history->peer->name(); return TextWithEntities{ .text = name, - .entities = (history->chatListUnreadCount() > 0) + .entities = (history->chatListBadgesState().unread ? EntitiesInText{ { EntityType::Semibold, 0, int(name.size()), QString() }, { EntityType::PlainLink, 0, int(name.size()), QString() }, } - : EntitiesInText{} + : EntitiesInText{}), }; }; const auto shown = int(peers.size()); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 5b079c732..050bb5d37 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -99,156 +99,49 @@ void PaintRowDate( PaintRowTopRight(p, dt, rectForName, context); } -void PaintNarrowCounter( +int PaintBadges( QPainter &p, const PaintContext &context, - bool displayUnreadCounter, - bool displayUnreadMark, - bool displayMentionBadge, - bool displayReactionBadge, - int unreadCount, - bool unreadMuted, - bool mentionOrReactionMuted) { - auto skipBeforeMention = 0; - if (displayUnreadCounter || displayUnreadMark) { - const auto counter = (unreadCount > 0) - ? QString::number(unreadCount) + BadgesState badgesState, + int right, + int top, + bool displayPinnedIcon = false, + int pinnedIconTop = 0) { + auto initial = right; + if (badgesState.unread) { + UnreadBadgeStyle st; + st.active = context.active; + st.selected = context.selected; + st.muted = badgesState.unreadMuted; + const auto counter = (badgesState.unreadCounter > 0) + ? QString::number(badgesState.unreadCounter) : QString(); - const auto allowDigits = (displayMentionBadge - || displayReactionBadge) - ? 1 - : 3; - const auto unreadRight = context.st->padding.left() - + context.st->photoSize; - const auto unreadTop = context.st->padding.top() - + context.st->photoSize - - st::dialogsUnreadHeight; - - UnreadBadgeStyle st; - st.active = context.active; - st.selected = context.selected; - st.muted = unreadMuted; - const auto badge = PaintUnreadBadge( - p, - counter, - unreadRight, - unreadTop, - st, - allowDigits); - skipBeforeMention += badge.width() + st.padding; - } - if (displayMentionBadge || displayReactionBadge) { - const auto counter = QString(); - const auto unreadRight = context.st->padding.left() - + context.st->photoSize - - skipBeforeMention; - const auto unreadTop = context.st->padding.top() - + context.st->photoSize - - st::dialogsUnreadHeight; - - UnreadBadgeStyle st; - st.sizeId = displayMentionBadge - ? UnreadBadgeSize::Dialogs - : UnreadBadgeSize::ReactionInDialogs; - st.active = context.active; - st.selected = context.selected; - st.muted = mentionOrReactionMuted; - st.padding = 0; - st.textTop = 0; - const auto badge = PaintUnreadBadge( - p, - counter, - unreadRight, - unreadTop, - st); - (displayMentionBadge - ? (st.active - ? st::dialogsUnreadMentionActive - : st.selected - ? st::dialogsUnreadMentionOver - : st::dialogsUnreadMention) - : (st.active - ? st::dialogsUnreadReactionActive - : st.selected - ? st::dialogsUnreadReactionOver - : st::dialogsUnreadReaction)).paintInCenter(p, badge); - } -} - -int PaintWideCounter( - QPainter &p, - const PaintContext &context, - int texttop, - int availableWidth, - bool displayUnreadCounter, - bool displayUnreadMark, - bool displayMentionBadge, - bool displayReactionBadge, - bool displayPinnedIcon, - int unreadCount, - bool unreadMuted, - bool mentionOrReactionMuted) { - const auto initial = availableWidth; - if (displayUnreadCounter || displayUnreadMark) { - const auto counter = (unreadCount > 0) - ? QString::number(unreadCount) - : QString(); - const auto unreadRight = context.width - context.st->padding.right(); - const auto unreadTop = texttop - + st::dialogsTextFont->ascent - - st::dialogsUnreadFont->ascent - - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2; - - UnreadBadgeStyle st; - st.active = context.active; - st.selected = context.selected; - st.muted = unreadMuted; - const auto badge = PaintUnreadBadge( - p, - counter, - unreadRight, - unreadTop, - st); - availableWidth -= badge.width() + st.padding; + const auto badge = PaintUnreadBadge(p, counter, right, top, st); + right -= badge.width() + st.padding; } else if (displayPinnedIcon) { const auto &icon = context.active ? st::dialogsPinnedIconActive : context.selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon; - icon.paint( - p, - context.width - context.st->padding.right() - icon.width(), - texttop, - context.width); - availableWidth -= icon.width() + st::dialogsUnreadPadding; + icon.paint(p, right - icon.width(), pinnedIconTop, context.width); + right -= icon.width() + st::dialogsUnreadPadding; } - if (displayMentionBadge || displayReactionBadge) { - const auto counter = QString(); - const auto unreadRight = context.width - - context.st->padding.right() - - (initial - availableWidth); - const auto unreadTop = texttop - + st::dialogsTextFont->ascent - - st::dialogsUnreadFont->ascent - - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2; - + if (badgesState.mention || badgesState.reaction) { UnreadBadgeStyle st; - st.sizeId = displayMentionBadge + st.sizeId = badgesState.mention ? UnreadBadgeSize::Dialogs : UnreadBadgeSize::ReactionInDialogs; st.active = context.active; st.selected = context.selected; - st.muted = mentionOrReactionMuted; + st.muted = badgesState.mention + ? badgesState.mentionMuted + : badgesState.reactionMuted; st.padding = 0; st.textTop = 0; - const auto badge = PaintUnreadBadge( - p, - counter, - unreadRight, - unreadTop, - st); - (displayMentionBadge + const auto counter = QString(); + const auto badge = PaintUnreadBadge(p, counter, right, top, st); + (badgesState.mention ? (st.active ? st::dialogsUnreadMentionActive : st.selected @@ -259,11 +152,46 @@ int PaintWideCounter( : st.selected ? st::dialogsUnreadReactionOver : st::dialogsUnreadReaction)).paintInCenter(p, badge); - availableWidth -= badge.width() - + st.padding - + st::dialogsUnreadPadding; + right -= badge.width() + st.padding + st::dialogsUnreadPadding; } - return availableWidth; + return (initial - right); +} + +void PaintNarrowCounter( + QPainter &p, + const PaintContext &context, + BadgesState badgesState) { + const auto top = context.st->padding.top() + + context.st->photoSize + - st::dialogsUnreadHeight; + PaintBadges( + p, + context, + badgesState, + context.st->padding.left() + context.st->photoSize, + top); +} + +int PaintWideCounter( + QPainter &p, + const PaintContext &context, + BadgesState badgesState, + int texttop, + int availableWidth, + bool displayPinnedIcon) { + const auto top = texttop + + st::dialogsTextFont->ascent + - st::dialogsUnreadFont->ascent + - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2; + const auto used = PaintBadges( + p, + context, + badgesState, + context.width - context.st->padding.right(), + top, + displayPinnedIcon, + texttop); + return availableWidth - used; } void PaintListEntryText( @@ -309,7 +237,7 @@ enum class Flag { }; inline constexpr bool is_flag_type(Flag) { return true; } -template +template void PaintRow( Painter &p, not_null row, @@ -325,9 +253,9 @@ void PaintRow( const Data::Draft *draft, QDateTime date, const PaintContext &context, + BadgesState badgesState, base::flags flags, - PaintItemCallback &&paintItemCallback, - PaintCounterCallback &&paintCounterCallback) { + PaintItemCallback &&paintItemCallback) { const auto supportMode = entry->session().supportMode(); if (supportMode) { draft = nullptr; @@ -383,7 +311,7 @@ void PaintRow( auto nameleft = context.st->nameLeft; if (context.width <= nameleft) { if (!draft && item && !item->isEmpty()) { - paintCounterCallback(); + PaintNarrowCounter(p, context, badgesState); } return; } @@ -891,12 +819,10 @@ void RowPainter::Paint( const auto history = row->history(); const auto thread = row->thread(); const auto peer = history ? history->peer.get() : nullptr; - const auto unreadCount = entry->chatListUnreadCount(); - const auto unreadMark = entry->chatListUnreadMark(); - const auto unreadMuted = entry->chatListMutedBadge(); + const auto badgesState = entry->chatListBadgesState(); const auto item = entry->chatListMessage(); const auto cloudDraft = [&]() -> const Data::Draft*{ - if (thread && (!item || (!unreadCount && !unreadMark))) { + if (thread && (!item || !badgesState.unread)) { // Draw item, if there are unread messages. const auto draft = thread->owningHistory()->cloudDraft( thread->topicRootId()); @@ -919,30 +845,7 @@ void RowPainter::Paint( ? base::unixtime::parse(cloudDraft->date) : QDateTime(); }(); - const auto displayMentionBadge = thread - && thread->unreadMentions().has(); - const auto displayReactionBadge = !displayMentionBadge - && thread - && thread->unreadReactions().has(); - const auto mentionOrReactionMuted = (entry->folder() != nullptr) - || (!displayMentionBadge && unreadMuted); - const auto displayUnreadCounter = [&] { - if (displayMentionBadge - && unreadCount == 1 - && item - && item->isUnreadMention()) { - return false; - } - return (unreadCount > 0); - }(); - const auto displayUnreadMark = !displayUnreadCounter - && !displayMentionBadge - && history - && unreadMark; - const auto displayPinnedIcon = !displayUnreadCounter - && !displayMentionBadge - && !displayReactionBadge - && !displayUnreadMark + const auto displayPinnedIcon = badgesState.empty() && entry->isPinnedDialog(context.filter) && (context.filter || !entry->fixedOnTopIndex()); @@ -951,8 +854,7 @@ void RowPainter::Paint( ? history->peer->migrateTo() : history->peer.get()) : nullptr; - const auto allowUserOnline = !context.narrow - || (!displayUnreadCounter && !displayUnreadMark); + const auto allowUserOnline = !context.narrow || badgesState.empty(); const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0)) | (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0)) | (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0)); @@ -961,16 +863,10 @@ void RowPainter::Paint( const auto availableWidth = PaintWideCounter( p, context, + badgesState, texttop, namewidth, - displayUnreadCounter, - displayUnreadMark, - displayMentionBadge, - displayReactionBadge, - displayPinnedIcon, - unreadCount, - unreadMuted, - mentionOrReactionMuted); + displayPinnedIcon); const auto &color = context.active ? st::dialogsTextFgServiceActive : context.selected @@ -1008,18 +904,6 @@ void RowPainter::Paint( view->paint(p, rect, context); } }; - const auto paintCounterCallback = [&] { - PaintNarrowCounter( - p, - context, - displayUnreadCounter, - displayUnreadMark, - displayMentionBadge, - displayReactionBadge, - unreadCount, - unreadMuted, - mentionOrReactionMuted); - }; PaintRow( p, row, @@ -1027,7 +911,7 @@ void RowPainter::Paint( row->key(), videoUserpic, from, - entry->chatListBadge(), + entry->chatListPeerBadge(), [=] { history->updateChatListEntry(); }, entry->chatListNameText(), nullptr, @@ -1035,9 +919,9 @@ void RowPainter::Paint( cloudDraft, displayDate, context, + badgesState, flags, - paintItemCallback, - paintCounterCallback); + paintItemCallback); } void RowPainter::Paint( @@ -1078,22 +962,9 @@ void RowPainter::Paint( return {}; }(); - const auto unreadCount = context.displayUnreadInfo - ? history->chatListUnreadCount() - : 0; - const auto unreadMark = context.displayUnreadInfo - && history->chatListUnreadMark(); - const auto unreadMuted = history->chatListMutedBadge(); - const auto mentionOrReactionMuted = (history->folder() != nullptr); - const auto displayMentionBadge = context.displayUnreadInfo - && history->unreadMentions().has(); - const auto displayReactionBadge = context.displayUnreadInfo - && !displayMentionBadge - && history->unreadReactions().has(); - const auto displayUnreadCounter = (unreadCount > 0); - const auto displayUnreadMark = !displayUnreadCounter - && !displayMentionBadge - && unreadMark; + const auto badgesState = context.displayUnreadInfo + ? history->chatListBadgesState() + : BadgesState(); const auto displayPinnedIcon = false; const auto paintItemCallback = [&](int nameleft, int namewidth) { @@ -1101,16 +972,10 @@ void RowPainter::Paint( const auto availableWidth = PaintWideCounter( p, context, + badgesState, texttop, namewidth, - displayUnreadCounter, - displayUnreadMark, - displayMentionBadge, - displayReactionBadge, - displayPinnedIcon, - unreadCount, - unreadMuted, - mentionOrReactionMuted); + displayPinnedIcon); const auto itemRect = QRect( nameleft, @@ -1123,18 +988,6 @@ void RowPainter::Paint( } row->itemView().paint(p, itemRect, context); }; - const auto paintCounterCallback = [&] { - PaintNarrowCounter( - p, - context, - displayUnreadCounter, - displayUnreadMark, - displayMentionBadge, - displayReactionBadge, - unreadCount, - unreadMuted, - mentionOrReactionMuted); - }; const auto showSavedMessages = history->peer->isSelf() && !row->searchInChat(); const auto showRepliesMessages = history->peer->isRepliesChat() @@ -1156,9 +1009,9 @@ void RowPainter::Paint( cloudDraft, ItemDateTime(item), context, + badgesState, flags, - paintItemCallback, - paintCounterCallback); + paintItemCallback); } QRect RowPainter::SendActionAnimationRect( diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 58bf18976..4ffeecc2a 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -1693,11 +1693,6 @@ int History::unreadCount() const { return _unreadCount ? *_unreadCount : 0; } -int History::unreadCountForBadge() const { - const auto result = unreadCount(); - return (!result && unreadMark()) ? 1 : result; -} - bool History::unreadCountKnown() const { return _unreadCount.has_value(); } @@ -1708,14 +1703,7 @@ void History::setUnreadCount(int newUnreadCount) { if (_unreadCount == newUnreadCount) { return; } - const auto wasForBadge = (unreadCountForBadge() > 0); - const auto refresher = gsl::finally([&] { - if (wasForBadge != (unreadCountForBadge() > 0)) { - owner().chatsFilters().refreshHistory(this); - } - session().changes().historyUpdated(this, UpdateFlag::UnreadView); - }); - const auto notifier = unreadStateChangeNotifier(true); + const auto notifier = unreadStateChangeNotifier(!peer->isForum()); _unreadCount = newUnreadCount; const auto lastOutgoing = [&] { @@ -1753,26 +1741,22 @@ void History::setUnreadMark(bool unread) { if (unreadMark() == unread) { return; } - const auto noUnreadMessages = !unreadCount(); - const auto refresher = gsl::finally([&] { - if (inChatList() && noUnreadMessages) { - owner().chatsFilters().refreshHistory(this); - updateChatListEntry(); - } - session().changes().historyUpdated(this, UpdateFlag::UnreadView); - }); - const auto notifier = unreadStateChangeNotifier(noUnreadMessages); - Thread::setUnreadMark(unread); + const auto notifier = unreadStateChangeNotifier( + !unreadCount() && !peer->isForum()); + Thread::setUnreadMarkFlag(unread); } void History::setFakeUnreadWhileOpened(bool enabled) { - if (_fakeUnreadWhileOpened == enabled - || (enabled - && (!inChatList() - || (!unreadCount() - && !unreadMark() - && !unreadMentions().has())))) { + if (_fakeUnreadWhileOpened == enabled) { return; + } else if (enabled) { + if (!inChatList()) { + return; + } + const auto state = chatListBadgesState(); + if (!state.unread && !state.mention) { + return; + } } _fakeUnreadWhileOpened = enabled; owner().chatsFilters().refreshHistory(this); @@ -1785,19 +1769,18 @@ void History::setFakeUnreadWhileOpened(bool enabled) { void History::setMuted(bool muted) { if (this->muted() == muted) { return; + } else { + const auto state = peer->isForum() + ? Dialogs::BadgesState() + : computeBadgesState(); + const auto notify = (state.unread || state.reaction); + const auto notifier = unreadStateChangeNotifier(notify); + Thread::setMuted(muted); } - const auto refresher = gsl::finally([&] { - if (inChatList()) { - owner().chatsFilters().refreshHistory(this); - updateChatListEntry(); - } - session().changes().peerUpdated( - peer, - Data::PeerUpdate::Flag::Notifications); - }); - const auto notify = (unreadCountForBadge() > 0); - const auto notifier = unreadStateChangeNotifier(notify); - Thread::setMuted(muted); + session().changes().peerUpdated( + peer, + Data::PeerUpdate::Flag::Notifications); + owner().chatsFilters().refreshHistory(this); if (const auto forum = peer->forum()) { owner().notifySettings().forumParentMuteUpdated(forum); } @@ -1899,6 +1882,33 @@ int History::chatListNameVersion() const { return peer->nameVersion(); } +void History::hasUnreadMentionChanged(bool has) { + if (peer->isForum()) { + return; + } + auto was = chatListUnreadState(); + if (has) { + was.mentions = 0; + } else { + was.mentions = 1; + } + notifyUnreadStateChange(was); +} + +void History::hasUnreadReactionChanged(bool has) { + if (peer->isForum()) { + return; + } + auto was = chatListUnreadState(); + if (has) { + was.reactions = was.reactionsMuted = 0; + } else { + was.reactions = 1; + was.reactionsMuted = muted() ? was.reactions : 0; + } + notifyUnreadStateChange(was); +} + void History::applyPinnedUpdate(const MTPDupdateDialogPinned &data) { const auto folderId = data.vfolder_id().value_or_empty(); if (!folderKnown()) { @@ -1998,10 +2008,7 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) { } void History::addUnreadBar() { - if (_unreadBarView || !_firstUnreadView || !unreadCount()) { - return; - } - if (const auto count = chatListUnreadCount()) { + if (!_unreadBarView && _firstUnreadView && unreadCount()) { _unreadBarView = _firstUnreadView; _unreadBarView->createUnreadBar(tr::lng_unread_bar_some()); } @@ -2066,41 +2073,6 @@ History *History::migrateSibling() const { return owner().historyLoaded(addFromId); } -int History::chatListUnreadCount() const { - if (peer->isForum()) { - const auto state = chatListUnreadState(); - return state.marks - + (Core::App().settings().countUnreadMessages() - ? state.messages - : state.chats); - } - const auto result = unreadCount(); - if (const auto migrated = migrateSibling()) { - return result + migrated->unreadCount(); - } - return result; -} - -bool History::chatListUnreadMark() const { - if (unreadMark()) { - return true; - } else if (const auto migrated = migrateSibling()) { - return migrated->unreadMark(); - } - return false; -} - -bool History::chatListMutedBadge() const { - if (const auto forum = peer->forum()) { - const auto state = forum->topicsList()->unreadState(); - return (state.marksMuted >= state.marks) - && (Core::App().settings().countUnreadMessages() - ? (state.messagesMuted >= state.messages) - : (state.chatsMuted >= state.chats)); - } - return muted(); -} - Dialogs::UnreadState History::chatListUnreadState() const { if (const auto forum = peer->forum()) { return forum->topicsList()->unreadState(); @@ -2108,17 +2080,47 @@ Dialogs::UnreadState History::chatListUnreadState() const { return computeUnreadState(); } +Dialogs::BadgesState History::chatListBadgesState() const { + if (const auto forum = peer->forum()) { + return adjustBadgesStateByFolder( + Dialogs::BadgesForUnread( + forum->topicsList()->unreadState(), + Dialogs::CountInBadge::Chats, + Dialogs::IncludeInBadge::UnmutedOrAll)); + } + return computeBadgesState(); +} + +Dialogs::BadgesState History::computeBadgesState() const { + return adjustBadgesStateByFolder( + Dialogs::BadgesForUnread( + computeUnreadState(), + Dialogs::CountInBadge::Messages, + Dialogs::IncludeInBadge::All)); +} + +Dialogs::BadgesState History::adjustBadgesStateByFolder( + Dialogs::BadgesState state) const { + if (folder()) { + state.mentionMuted = state.reactionMuted = state.unreadMuted = true; + } + return state; +} + Dialogs::UnreadState History::computeUnreadState() const { auto result = Dialogs::UnreadState(); const auto count = _unreadCount.value_or(0); const auto mark = !count && unreadMark(); const auto muted = this->muted(); result.messages = count; - result.messagesMuted = muted ? count : 0; result.chats = count ? 1 : 0; - result.chatsMuted = (count && muted) ? 1 : 0; result.marks = mark ? 1 : 0; - result.marksMuted = (mark && muted) ? 1 : 0; + result.mentions = unreadMentions().has() ? 1 : 0; + result.reactions = unreadReactions().has() ? 1 : 0; + result.messagesMuted = muted ? result.messages : 0; + result.chatsMuted = muted ? result.chats : 0; + result.marksMuted = muted ? result.marks : 0; + result.reactionsMuted = muted ? result.reactions : 0; result.known = _unreadCount.has_value(); return result; } @@ -2908,7 +2910,6 @@ void History::forumChanged(Data::Forum *old) { return (_flags & Flag::IsForum) && inChatList(); }) | rpl::start_with_next([=](const Dialogs::UnreadState &old) { notifyUnreadStateChange(old); - updateChatListEntryPostponed(); }, forum->lifetime()); } else { _flags &= ~Flag::IsForum; diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 056cc3d8b..c81766e73 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -248,10 +248,9 @@ public: [[nodiscard]] bool unreadCountRefreshNeeded(MsgId readTillId) const; void setUnreadCount(int newUnreadCount); - void setUnreadMark(bool unread) override; + void setUnreadMark(bool unread); void setFakeUnreadWhileOpened(bool enabled); [[nodiscard]] bool fakeUnreadWhileOpened() const; - [[nodiscard]] int unreadCountForBadge() const; // unreadCount || unreadMark ? 1 : 0. void setMuted(bool muted) override; void addUnreadBar(); void destroyUnreadBar(); @@ -380,10 +379,8 @@ public: int fixedOnTopIndex() const override; void updateChatListExistence() override; bool shouldBeInChatList() const override; - int chatListUnreadCount() const override; - bool chatListUnreadMark() const override; - bool chatListMutedBadge() const override; Dialogs::UnreadState chatListUnreadState() const override; + Dialogs::BadgesState chatListBadgesState() const override; HistoryItem *chatListMessage() const override; bool chatListMessageKnown() const override; void requestChatListMessage() override; @@ -574,11 +571,17 @@ private: HistoryService *insertJoinedMessage(); void insertMessageToBlocks(not_null item); + [[nodiscard]] Dialogs::BadgesState computeBadgesState() const; + [[nodiscard]] Dialogs::BadgesState adjustBadgesStateByFolder( + Dialogs::BadgesState state) const; [[nodiscard]] Dialogs::UnreadState computeUnreadState() const; void setFolderPointer(Data::Folder *folder); int chatListNameVersion() const override; + void hasUnreadMentionChanged(bool has) override; + void hasUnreadReactionChanged(bool has) override; + const std::unique_ptr _delegateMixin; Flags _flags = 0; diff --git a/Telegram/SourceFiles/history/history_unread_things.cpp b/Telegram/SourceFiles/history/history_unread_things.cpp index 5bf42c4c8..928a74123 100644 --- a/Telegram/SourceFiles/history/history_unread_things.cpp +++ b/Telegram/SourceFiles/history/history_unread_things.cpp @@ -67,13 +67,12 @@ void Proxy::setCount(int count) { list.setCount(count); } const auto has = (count > 0); - if (has != had) { + if (has != had && _thread->inChatList()) { if (_type == Type::Mentions) { - if (const auto history = _thread->asHistory()) { - _thread->owner().chatsFilters().refreshHistory(history); - } + _thread->hasUnreadMentionChanged(has); + } else if (_type == Type::Reactions) { + _thread->hasUnreadReactionChanged(has); } - _thread->updateChatListEntry(); } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 3cb580dc7..373fd9e00 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2257,21 +2257,17 @@ void HistoryWidget::showHistory( if (!_history->folderKnown()) { session().data().histories().requestDialogEntry(_history); } - if (_history->chatListUnreadMark()) { - _history->owner().histories().changeDialogUnreadMark( + + // Must be done before unreadCountUpdated(), or we auto-close. + if (_history->unreadMark()) { + session().data().histories().changeDialogUnreadMark( _history, false); - if (_migrated) { - _migrated->owner().histories().changeDialogUnreadMark( - _migrated, - false); - } - - // Must be done before unreadCountUpdated(), or we auto-close. - _history->setUnreadMark(false); - if (_migrated) { - _migrated->setUnreadMark(false); - } + } + if (_migrated && _migrated->unreadMark()) { + session().data().histories().changeDialogUnreadMark( + _migrated, + false); } unreadCountUpdated(); // set _historyDown badge. showAboutTopPromotion(); @@ -2913,7 +2909,7 @@ void HistoryWidget::maybeMarkReactionsRead(not_null item) { } void HistoryWidget::unreadCountUpdated() { - if (_history->chatListUnreadMark()) { + if (_history->unreadMark() || (_migrated && _migrated->unreadMark())) { crl::on_main(this, [=, history = _history] { if (history == _history) { closeCurrent(); @@ -2922,7 +2918,7 @@ void HistoryWidget::unreadCountUpdated() { }); } else { _cornerButtons.updateJumpDownVisibility( - _history->chatListUnreadCount()); + _history->chatListBadgesState().unreadCounter); } } diff --git a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm index 0e026ee69..218104689 100644 --- a/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm +++ b/Telegram/SourceFiles/platform/mac/touchbar/items/mac_pinned_chats_item.mm @@ -91,16 +91,16 @@ QImage ArchiveUserpic(not_null folder) { QImage UnreadBadge(not_null peer) { const auto history = peer->owner().history(peer->id); - const auto count = history->unreadCountForBadge(); - if (!count) { + const auto state = history->chatListBadgesState(); + if (!state.unread) { return QImage(); } - const auto unread = history->unreadMark() - ? QString() - : QString::number(count); + const auto counter = (state.unreadCounter > 0) + ? QString::number(state.unreadCounter) + : QString(); Dialogs::Ui::UnreadBadgeStyle unreadSt; unreadSt.sizeId = Dialogs::Ui::UnreadBadgeSize::TouchBar; - unreadSt.muted = history->muted(); + unreadSt.muted = state.unreadMuted; // Use constant values to draw badge regardless of cConfigScale(). unreadSt.size = kUnreadBadgeSize * cRetinaFactor(); unreadSt.padding = 4 * cRetinaFactor(); diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index a50595f42..165d82131 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -579,10 +579,10 @@ void MainMenu::setupArchive() { return folder->owner().chatsList(folder)->unreadStateChanges(); }) | rpl::flatten_latest() | rpl::to_empty) | rpl::map([=] { const auto loaded = folder(); - return Badge::UnreadBadge{ - loaded ? loaded->chatListUnreadCount() : 0, - true, - }; + const auto state = loaded + ? loaded->chatListBadgesState() + : Dialogs::BadgesState(); + return Badge::UnreadBadge{ state.unreadCounter, true }; })); controller->session().data().chatsListChanges( diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 57d781649..3e71d3198 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -112,8 +112,7 @@ void SetActionText(not_null action, rpl::producer &&text) { } [[nodiscard]] bool IsUnreadThread(not_null thread) { - return (thread->chatListUnreadCount() > 0) - || (thread->chatListUnreadMark()); + return thread->chatListBadgesState().unread; } void MarkAsReadThread(not_null thread) { @@ -1739,7 +1738,7 @@ void MenuAddMarkAsReadChatListAction( const PeerMenuCallback &addAction) { // There is no async to make weak from controller. const auto unreadState = list()->unreadState(); - if (unreadState.empty()) { + if (!unreadState.messages && !unreadState.marks && !unreadState.chats) { return; }