mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-29 00:43:10 +02:00
Correctly mark monoforum chats as read.
This commit is contained in:
parent
7f7b764f7b
commit
f4582ddf36
9 changed files with 135 additions and 8 deletions
|
@ -711,6 +711,7 @@ void Histories::sendReadRequest(not_null<History*> history, State &state) {
|
||||||
} else {
|
} else {
|
||||||
Assert(!state->sentReadTill || state->sentReadTill > tillId);
|
Assert(!state->sentReadTill || state->sentReadTill > tillId);
|
||||||
}
|
}
|
||||||
|
history->validateMonoforumUnread(tillId);
|
||||||
sendReadRequests();
|
sendReadRequests();
|
||||||
finish();
|
finish();
|
||||||
};
|
};
|
||||||
|
|
|
@ -521,6 +521,27 @@ auto SavedMessages::recentSublists() const
|
||||||
return _lastSublists;
|
return _lastSublists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SavedMessages::markUnreadCountsUnknown(MsgId readTillId) {
|
||||||
|
for (const auto &[peer, sublist] : _sublists) {
|
||||||
|
if (sublist->unreadCountCurrent() > 0) {
|
||||||
|
sublist->setInboxReadTill(readTillId, std::nullopt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavedMessages::updateUnreadCounts(
|
||||||
|
MsgId readTillId,
|
||||||
|
const base::flat_map<not_null<SavedSublist*>, int> &counts) {
|
||||||
|
for (const auto &[peer, sublist] : _sublists) {
|
||||||
|
const auto raw = sublist.get();
|
||||||
|
const auto i = counts.find(raw);
|
||||||
|
const auto count = (i != end(counts)) ? i->second : 0;
|
||||||
|
if (raw->unreadCountCurrent() != count) {
|
||||||
|
raw->setInboxReadTill(readTillId, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<> SavedMessages::destroyed() const {
|
rpl::producer<> SavedMessages::destroyed() const {
|
||||||
if (!_parentChat) {
|
if (!_parentChat) {
|
||||||
return rpl::never<>();
|
return rpl::never<>();
|
||||||
|
|
|
@ -70,6 +70,11 @@ public:
|
||||||
[[nodiscard]] auto recentSublists() const
|
[[nodiscard]] auto recentSublists() const
|
||||||
-> const std::vector<not_null<SavedSublist*>> &;
|
-> const std::vector<not_null<SavedSublist*>> &;
|
||||||
|
|
||||||
|
void markUnreadCountsUnknown(MsgId readTillId);
|
||||||
|
void updateUnreadCounts(
|
||||||
|
MsgId readTillId,
|
||||||
|
const base::flat_map<not_null<SavedSublist*>, int> &counts);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime();
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "data/data_saved_sublist.h"
|
#include "data/data_saved_sublist.h"
|
||||||
|
|
||||||
|
#include "api/api_unread_things.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
@ -61,7 +62,7 @@ SavedSublist::~SavedSublist() {
|
||||||
if (_readRequestTimer.isActive()) {
|
if (_readRequestTimer.isActive()) {
|
||||||
sendReadTillRequest();
|
sendReadTillRequest();
|
||||||
}
|
}
|
||||||
// session().api().unreadThings().cancelRequests(this);
|
session().api().unreadThings().cancelRequests(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SavedSublist::inMonoforum() const {
|
bool SavedSublist::inMonoforum() const {
|
||||||
|
@ -444,6 +445,9 @@ void SavedSublist::setInboxReadTill(
|
||||||
&& !_list.empty()
|
&& !_list.empty()
|
||||||
&& _inboxReadTillId >= _list.front()) {
|
&& _inboxReadTillId >= _list.front()) {
|
||||||
unreadCount = 0;
|
unreadCount = 0;
|
||||||
|
} else if (_lastServerMessage.value_or(nullptr)
|
||||||
|
&& (*_lastServerMessage)->id <= newReadTillId) {
|
||||||
|
unreadCount = 0;
|
||||||
}
|
}
|
||||||
if (_unreadCount.current() != unreadCount
|
if (_unreadCount.current() != unreadCount
|
||||||
&& (changed || unreadCount.has_value())) {
|
&& (changed || unreadCount.has_value())) {
|
||||||
|
@ -646,10 +650,11 @@ void SavedSublist::sendReadTillRequest() {
|
||||||
const auto api = &_parent->session().api();
|
const auto api = &_parent->session().api();
|
||||||
api->request(base::take(_readRequestId)).cancel();
|
api->request(base::take(_readRequestId)).cancel();
|
||||||
|
|
||||||
|
_sentReadTill = computeInboxReadTillFull();
|
||||||
_readRequestId = api->request(MTPmessages_ReadSavedHistory(
|
_readRequestId = api->request(MTPmessages_ReadSavedHistory(
|
||||||
parentChat->input,
|
parentChat->input,
|
||||||
sublistPeer()->input,
|
sublistPeer()->input,
|
||||||
MTP_int(computeInboxReadTillFull())
|
MTP_int(_sentReadTill.bare)
|
||||||
)).done(crl::guard(this, [=] {
|
)).done(crl::guard(this, [=] {
|
||||||
_readRequestId = 0;
|
_readRequestId = 0;
|
||||||
reloadUnreadCountIfNeeded();
|
reloadUnreadCountIfNeeded();
|
||||||
|
@ -708,6 +713,20 @@ void SavedSublist::applyMonoforumDialog(
|
||||||
setInboxReadTill(
|
setInboxReadTill(
|
||||||
data.vread_inbox_max_id().v,
|
data.vread_inbox_max_id().v,
|
||||||
data.vunread_count().v);
|
data.vunread_count().v);
|
||||||
|
if (!unreadCountKnown() && !_readRequestId) {
|
||||||
|
// We got read_inbox_max_id < than our current inboxReadTillId,
|
||||||
|
// we need either to send a read request with this new value,
|
||||||
|
// or to downgrade inboxReadTillId locally.
|
||||||
|
if (_sentReadTill < computeInboxReadTillFull()) {
|
||||||
|
sendReadTillRequest();
|
||||||
|
} else {
|
||||||
|
// Just if nothing else helps.
|
||||||
|
_inboxReadTillId = 0;
|
||||||
|
setInboxReadTill(
|
||||||
|
data.vread_inbox_max_id().v,
|
||||||
|
data.vunread_count().v);
|
||||||
|
}
|
||||||
|
}
|
||||||
setOutboxReadTill(data.vread_outbox_max_id().v);
|
setOutboxReadTill(data.vread_outbox_max_id().v);
|
||||||
unreadReactions().setCount(data.vunread_reactions_count().v);
|
unreadReactions().setCount(data.vunread_reactions_count().v);
|
||||||
setUnreadMark(data.is_unread_mark());
|
setUnreadMark(data.is_unread_mark());
|
||||||
|
|
|
@ -184,6 +184,7 @@ private:
|
||||||
|
|
||||||
base::Timer _readRequestTimer;
|
base::Timer _readRequestTimer;
|
||||||
mtpRequestId _readRequestId = 0;
|
mtpRequestId _readRequestId = 0;
|
||||||
|
MsgId _sentReadTill = 0;
|
||||||
|
|
||||||
mtpRequestId _reloadUnreadCountRequestId = 0;
|
mtpRequestId _reloadUnreadCountRequestId = 0;
|
||||||
|
|
||||||
|
|
|
@ -3108,8 +3108,70 @@ void History::applyDialogTopMessage(MsgId topMessageId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void History::tryMarkMonoforumIntervalRead(
|
||||||
|
MsgId wasInboxReadBefore,
|
||||||
|
MsgId nowInboxReadBefore) {
|
||||||
|
if (!amMonoforumAdmin() || (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::SavedSublist*>, 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 sublist = item->savedSublist()) {
|
||||||
|
++counts[sublist];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const auto monoforum = peer->monoforum()) {
|
||||||
|
monoforum->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 sublist = item->savedSublist()) {
|
||||||
|
const auto unread = sublist->unreadCountCurrent();
|
||||||
|
if (unread > 0) {
|
||||||
|
sublist->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::MonoforumUnreadInvalidatePending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::validateMonoforumUnread(MsgId readTillId) {
|
||||||
|
if (!(_flags & Flag::MonoforumUnreadInvalidatePending)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_flags &= ~Flag::MonoforumUnreadInvalidatePending;
|
||||||
|
if (!amMonoforumAdmin()) {
|
||||||
|
return;
|
||||||
|
} else if (const auto monoforum = peer->monoforum()) {
|
||||||
|
monoforum->markUnreadCountsUnknown(readTillId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void History::setInboxReadTill(MsgId upTo) {
|
void History::setInboxReadTill(MsgId upTo) {
|
||||||
if (_inboxReadBefore) {
|
if (_inboxReadBefore) {
|
||||||
|
tryMarkMonoforumIntervalRead(*_inboxReadBefore, upTo + 1);
|
||||||
accumulate_max(*_inboxReadBefore, upTo + 1);
|
accumulate_max(*_inboxReadBefore, upTo + 1);
|
||||||
} else {
|
} else {
|
||||||
_inboxReadBefore = upTo + 1;
|
_inboxReadBefore = upTo + 1;
|
||||||
|
|
|
@ -430,6 +430,10 @@ public:
|
||||||
// Interface for Data::Histories.
|
// Interface for Data::Histories.
|
||||||
void setInboxReadTill(MsgId upTo);
|
void setInboxReadTill(MsgId upTo);
|
||||||
std::optional<int> countStillUnreadLocal(MsgId readTillId) const;
|
std::optional<int> countStillUnreadLocal(MsgId readTillId) const;
|
||||||
|
void tryMarkMonoforumIntervalRead(
|
||||||
|
MsgId wasInboxReadBefore,
|
||||||
|
MsgId nowInboxReadBefore);
|
||||||
|
void validateMonoforumUnread(MsgId readTillId);
|
||||||
|
|
||||||
[[nodiscard]] bool isTopPromoted() const;
|
[[nodiscard]] bool isTopPromoted() const;
|
||||||
|
|
||||||
|
@ -466,7 +470,7 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class HistoryBlock;
|
friend class HistoryBlock;
|
||||||
|
|
||||||
enum class Flag : uchar {
|
enum class Flag : ushort {
|
||||||
HasPendingResizedItems = (1 << 0),
|
HasPendingResizedItems = (1 << 0),
|
||||||
PendingAllItemsResize = (1 << 1),
|
PendingAllItemsResize = (1 << 1),
|
||||||
IsTopPromoted = (1 << 2),
|
IsTopPromoted = (1 << 2),
|
||||||
|
@ -475,6 +479,7 @@ private:
|
||||||
FakeUnreadWhileOpened = (1 << 5),
|
FakeUnreadWhileOpened = (1 << 5),
|
||||||
HasPinnedMessages = (1 << 6),
|
HasPinnedMessages = (1 << 6),
|
||||||
ResolveChatListMessage = (1 << 7),
|
ResolveChatListMessage = (1 << 7),
|
||||||
|
MonoforumUnreadInvalidatePending = (1 << 8),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) {
|
friend inline constexpr auto is_flag_type(Flag) {
|
||||||
|
|
|
@ -3632,10 +3632,11 @@ void HistoryWidget::unreadCountUpdated() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const auto hideCounter = _history->isForum()
|
const auto hideCounter = _history->isForum()
|
||||||
|| _history->amMonoforumAdmin()
|
|
||||||
|| !_history->trackUnreadMessages();
|
|| !_history->trackUnreadMessages();
|
||||||
_cornerButtons.updateJumpDownVisibility(hideCounter
|
_cornerButtons.updateJumpDownVisibility(hideCounter
|
||||||
? 0
|
? 0
|
||||||
|
: _history->amMonoforumAdmin()
|
||||||
|
? _history->chatListUnreadState().messages
|
||||||
: _history->chatListBadgesState().unreadCounter);
|
: _history->chatListBadgesState().unreadCounter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,7 +349,6 @@ void SubsectionTabs::setupSlider(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slider->setSections({
|
slider->setSections({
|
||||||
.tabs = std::move(sections),
|
.tabs = std::move(sections),
|
||||||
.context = Core::TextContext({
|
.context = Core::TextContext({
|
||||||
|
@ -591,11 +590,24 @@ void SubsectionTabs::refreshSlice() {
|
||||||
const auto push = [&](not_null<Data::Thread*> thread) {
|
const auto push = [&](not_null<Data::Thread*> thread) {
|
||||||
const auto topic = thread->asTopic();
|
const auto topic = thread->asTopic();
|
||||||
const auto sublist = thread->asSublist();
|
const auto sublist = thread->asSublist();
|
||||||
|
const auto badges = [&] {
|
||||||
|
if (!topic && !sublist) {
|
||||||
|
return Dialogs::BadgesState();
|
||||||
|
} else if (thread->chatListUnreadState().known) {
|
||||||
|
return thread->chatListBadgesState();
|
||||||
|
}
|
||||||
|
const auto i = ranges::find(_slice, thread, &Item::thread);
|
||||||
|
if (i != end(_slice)) {
|
||||||
|
// While the unread count is unknown (possibly loading)
|
||||||
|
// we can preserve the old badges state, because it won't
|
||||||
|
// glitch that way when we stop knowing it for a moment.
|
||||||
|
return i->badges;
|
||||||
|
}
|
||||||
|
return thread->chatListBadgesState();
|
||||||
|
}();
|
||||||
slice.push_back({
|
slice.push_back({
|
||||||
.thread = thread,
|
.thread = thread,
|
||||||
.badges = ((topic || sublist)
|
.badges = badges,
|
||||||
? thread->chatListBadgesState()
|
|
||||||
: Dialogs::BadgesState()),
|
|
||||||
.iconId = topic ? topic->iconId() : DocumentId(),
|
.iconId = topic ? topic->iconId() : DocumentId(),
|
||||||
.name = thread->chatListName(),
|
.name = thread->chatListName(),
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue