diff --git a/Telegram/SourceFiles/data/data_forum.cpp b/Telegram/SourceFiles/data/data_forum.cpp index 3890b4c0ed..0a20f0aeac 100644 --- a/Telegram/SourceFiles/data/data_forum.cpp +++ b/Telegram/SourceFiles/data/data_forum.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_forum_icons.h" #include "data/data_forum_topic.h" +#include "data/data_replies_list.h" #include "data/notify/data_notify_settings.h" #include "history/history.h" #include "history/history_item.h" @@ -276,6 +277,33 @@ Thread *Forum::activeSubsectionThread() const { return _activeSubsectionTopic; } +void Forum::markUnreadCountsUnknown(MsgId readTillId) { + if (!channel()->useSubsectionTabs()) { + return; + } + for (const auto &[rootId, topic] : _topics) { + const auto replies = topic->replies(); + if (replies->unreadCountCurrent() > 0) { + replies->setInboxReadTill(readTillId, std::nullopt); + } + } +} + +void Forum::updateUnreadCounts( + MsgId readTillId, + const base::flat_map, int> &counts) { + if (!channel()->useSubsectionTabs()) { + return; + } + for (const auto &[rootId, topic] : _topics) { + const auto raw = topic.get(); + const auto replies = raw->replies(); + const auto i = counts.find(raw); + const auto count = (i != end(counts)) ? i->second : 0; + replies->setInboxReadTill(readTillId, count); + } +} + void Forum::listMessageChanged(HistoryItem *from, HistoryItem *to) { if (from || to) { reorderLastTopics(); diff --git a/Telegram/SourceFiles/data/data_forum.h b/Telegram/SourceFiles/data/data_forum.h index ae0cc2d1a5..cccacadeef 100644 --- a/Telegram/SourceFiles/data/data_forum.h +++ b/Telegram/SourceFiles/data/data_forum.h @@ -99,6 +99,11 @@ public: void saveActiveSubsectionThread(not_null thread); [[nodiscard]] Thread *activeSubsectionThread() const; + void markUnreadCountsUnknown(MsgId readTillId); + void updateUnreadCounts( + MsgId readTillId, + const base::flat_map, int> &counts); + [[nodiscard]] rpl::lifetime &lifetime() { return _lifetime; } diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index f114f6d433..30983b9347 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -713,7 +713,7 @@ void Histories::sendReadRequest(not_null history, State &state) { } else { Assert(!state->sentReadTill || state->sentReadTill > tillId); } - history->validateMonoforumUnread(tillId); + history->validateMonoAndForumUnread(tillId); sendReadRequests(); finish(); }; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index ed146023f4..88a786f38a 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel_admins.h" #include "data/data_changes.h" #include "data/data_chat_filters.h" +#include "data/data_replies_list.h" #include "data/data_send_action.h" #include "data/data_star_gift.h" #include "data/data_emoji_statuses.h" @@ -3156,6 +3157,58 @@ void History::applyDialogTopMessage(MsgId topMessageId) { } } +void History::tryMarkForumIntervalRead( + MsgId wasInboxReadBefore, + MsgId nowInboxReadBefore) { + if (!isForum() + || !peer->asChannel()->useSubsectionTabs() + || (nowInboxReadBefore <= wasInboxReadBefore)) { + return; + } else if (loadedAtBottom() && nowInboxReadBefore >= minMsgId()) { + // Count for each sublist how many messages are still not read. + auto counts = base::flat_map, int>(); + for (const auto &block : blocks) { + for (const auto &message : block->messages) { + const auto item = message->data(); + if (!item->isRegular() || item->id < nowInboxReadBefore) { + continue; + } + if (const auto topic = item->topic()) { + ++counts[topic]; + } + } + } + if (const auto forum = peer->forum()) { + forum->updateUnreadCounts(nowInboxReadBefore - 1, counts); + } + } else if (minMsgId() <= wasInboxReadBefore + && maxMsgId() >= nowInboxReadBefore) { + // Count for each sublist how many messages were read. + for (const auto &block : blocks) { + for (const auto &message : block->messages) { + const auto item = message->data(); + if (!item->isRegular() || item->id < wasInboxReadBefore) { + continue; + } else if (item->id >= nowInboxReadBefore) { + break; + } + if (const auto topic = item->topic()) { + const auto replies = topic->replies(); + const auto unread = replies->unreadCountCurrent(); + if (unread > 0) { + replies->setInboxReadTill(item->id, unread - 1); + } + } + } + } + } else { + // We can't invalidate sublist unread counts here, because no read + // request was yet sent to the server (so it can't return correct + // values yet), we need to do that after we send read request. + _flags |= Flag::MonoAndForumUnreadInvalidatePending; + } +} + void History::tryMarkMonoforumIntervalRead( MsgId wasInboxReadBefore, MsgId nowInboxReadBefore) { @@ -3201,24 +3254,29 @@ void History::tryMarkMonoforumIntervalRead( // We can't invalidate sublist unread counts here, because no read // request was yet sent to the server (so it can't return correct // values yet), we need to do that after we send read request. - _flags |= Flag::MonoforumUnreadInvalidatePending; + _flags |= Flag::MonoAndForumUnreadInvalidatePending; } } -void History::validateMonoforumUnread(MsgId readTillId) { - if (!(_flags & Flag::MonoforumUnreadInvalidatePending)) { +void History::validateMonoAndForumUnread(MsgId readTillId) { + if (!(_flags & Flag::MonoAndForumUnreadInvalidatePending)) { return; } - _flags &= ~Flag::MonoforumUnreadInvalidatePending; - if (!amMonoforumAdmin()) { - return; - } else if (const auto monoforum = peer->monoforum()) { - monoforum->markUnreadCountsUnknown(readTillId); + _flags &= ~Flag::MonoAndForumUnreadInvalidatePending; + if (isForum()) { + if (const auto forum = peer->forum()) { + forum->markUnreadCountsUnknown(readTillId); + } + } else if (amMonoforumAdmin()) { + if (const auto monoforum = peer->monoforum()) { + monoforum->markUnreadCountsUnknown(readTillId); + } } } void History::setInboxReadTill(MsgId upTo) { if (_inboxReadBefore) { + tryMarkForumIntervalRead(*_inboxReadBefore, upTo + 1); tryMarkMonoforumIntervalRead(*_inboxReadBefore, upTo + 1); accumulate_max(*_inboxReadBefore, upTo + 1); } else { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 047a341094..40ee83ceef 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -434,7 +434,10 @@ public: void tryMarkMonoforumIntervalRead( MsgId wasInboxReadBefore, MsgId nowInboxReadBefore); - void validateMonoforumUnread(MsgId readTillId); + void tryMarkForumIntervalRead( + MsgId wasInboxReadBefore, + MsgId nowInboxReadBefore); + void validateMonoAndForumUnread(MsgId readTillId); [[nodiscard]] bool isTopPromoted() const; @@ -480,7 +483,7 @@ private: FakeUnreadWhileOpened = (1 << 5), HasPinnedMessages = (1 << 6), ResolveChatListMessage = (1 << 7), - MonoforumUnreadInvalidatePending = (1 << 8), + MonoAndForumUnreadInvalidatePending = (1 << 8), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) {