2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-22 10:17:10 +00:00

Fix marking read in new forum layout.

This commit is contained in:
John Preston 2025-08-08 20:23:51 +04:00
parent 60f6ea3252
commit 87cdc22990
5 changed files with 105 additions and 11 deletions

View File

@ -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<not_null<ForumTopic*>, 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();

View File

@ -99,6 +99,11 @@ public:
void saveActiveSubsectionThread(not_null<Thread*> thread);
[[nodiscard]] Thread *activeSubsectionThread() const;
void markUnreadCountsUnknown(MsgId readTillId);
void updateUnreadCounts(
MsgId readTillId,
const base::flat_map<not_null<ForumTopic*>, int> &counts);
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}

View File

@ -713,7 +713,7 @@ void Histories::sendReadRequest(not_null<History*> history, State &state) {
} else {
Assert(!state->sentReadTill || state->sentReadTill > tillId);
}
history->validateMonoforumUnread(tillId);
history->validateMonoAndForumUnread(tillId);
sendReadRequests();
finish();
};

View File

@ -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<not_null<Data::ForumTopic*>, 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 {

View File

@ -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<Flag>;
friend inline constexpr auto is_flag_type(Flag) {