Fix reading of currently opened chat.

This commit is contained in:
John Preston 2020-02-19 19:35:26 +04:00
parent c04f3a7048
commit 5b7f7ed70e
8 changed files with 115 additions and 109 deletions

View File

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_cloud_themes.h" #include "data/data_cloud_themes.h"
#include "data/data_histories.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "core/core_cloud_password.h" #include "core/core_cloud_password.h"
#include "core/application.h" #include "core/application.h"
@ -4432,7 +4433,7 @@ void ApiWrap::userPhotosDone(
//} //}
void ApiWrap::sendAction(const SendAction &action) { void ApiWrap::sendAction(const SendAction &action) {
action.history->readInbox(); session().data().histories().readInbox(action.history);
action.history->getReadyFor(ShowAtTheEndMsgId); action.history->getReadyFor(ShowAtTheEndMsgId);
_sendActions.fire_copy(action); _sendActions.fire_copy(action);
} }
@ -4459,7 +4460,7 @@ void ApiWrap::forwardMessages(
const auto history = action.history; const auto history = action.history;
const auto peer = history->peer; const auto peer = history->peer;
history->readInbox(); session().data().histories().readInbox(history);
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = action.options.silent const auto silentPost = action.options.silent

View File

@ -63,10 +63,32 @@ void Histories::clearAll() {
_map.clear(); _map.clear();
} }
void Histories::readInboxTill( void Histories::readInbox(not_null<History*> history) {
not_null<History*> history, if (history->lastServerMessageKnown()) {
not_null<HistoryItem*> item) { const auto last = history->lastServerMessage();
readInboxTill(history, last ? last->id : 0);
return;
} else if (history->loadedAtBottom()) {
if (const auto lastId = history->maxMsgId()) {
readInboxTill(history, lastId);
return;
} else if (history->loadedAtTop()) {
readInboxTill(history, 0);
return;
}
}
session().api().requestDialogEntry(history, [=] {
Expects(history->lastServerMessageKnown());
const auto last = history->lastServerMessage();
readInboxTill(history, last ? last->id : 0);
});
}
void Histories::readInboxTill(not_null<HistoryItem*> item) {
const auto history = item->history();
if (!IsServerMsgId(item->id)) { if (!IsServerMsgId(item->id)) {
readClientSideMessage(item);
auto view = item->mainView(); auto view = item->mainView();
if (!view) { if (!view) {
return; return;
@ -102,15 +124,23 @@ void Histories::readInboxTill(
} }
void Histories::readInboxTill(not_null<History*> history, MsgId tillId) { void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
if (!history->readInboxTillNeedsRequest(tillId)) { readInboxTill(history, tillId, false);
return; }
} void Histories::readInboxTill(
const auto maybeState = lookup(history); not_null<History*> history,
if (maybeState && maybeState->readTill >= tillId) { MsgId tillId,
bool force) {
if (!history->readInboxTillNeedsRequest(tillId) && !force) {
return; return;
} else if (!force) {
const auto maybeState = lookup(history);
if (maybeState && maybeState->readTill >= tillId) {
return;
}
} }
const auto stillUnread = history->countStillUnreadLocal(tillId); const auto stillUnread = history->countStillUnreadLocal(tillId);
if (stillUnread if (!force
&& stillUnread
&& history->unreadCountKnown() && history->unreadCountKnown()
&& *stillUnread == history->unreadCount()) { && *stillUnread == history->unreadCount()) {
history->setInboxReadTill(tillId); history->setInboxReadTill(tillId);
@ -119,10 +149,12 @@ void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
auto &state = _states[history]; auto &state = _states[history];
const auto wasReadTill = state.readTill; const auto wasReadTill = state.readTill;
state.readTill = tillId; state.readTill = tillId;
if (!stillUnread) { if (force || !stillUnread || !*stillUnread) {
state.readWhen = 0; state.readWhen = 0;
sendReadRequests(); sendReadRequests();
return; if (!stillUnread) {
return;
}
} else if (!wasReadTill) { } else if (!wasReadTill) {
state.readWhen = crl::now() + kReadRequestTimeout; state.readWhen = crl::now() + kReadRequestTimeout;
if (!_readRequestsTimer.isActive()) { if (!_readRequestsTimer.isActive()) {
@ -134,6 +166,25 @@ void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
history->updateChatListEntry(); history->updateChatListEntry();
} }
void Histories::readInboxOnNewMessage(not_null<HistoryItem*> item) {
if (!IsServerMsgId(item->id)) {
readClientSideMessage(item);
} else {
readInboxTill(item->history(), item->id, true);
}
}
void Histories::readClientSideMessage(not_null<HistoryItem*> item) {
if (item->out() || !item->unread()) {
return;
}
const auto history = item->history();
item->markClientSideAsRead();
if (const auto unread = history->unreadCount()) {
history->setUnreadCount(unread - 1);
}
}
void Histories::sendPendingReadInbox(not_null<History*> history) { void Histories::sendPendingReadInbox(not_null<History*> history) {
if (const auto state = lookup(history)) { if (const auto state = lookup(history)) {
if (state->readTill && state->readWhen) { if (state->readTill && state->readWhen) {
@ -255,10 +306,11 @@ void Histories::checkPostponed(not_null<History*> history, int requestId) {
const auto action = chooseAction(*state, entry.second.type, true); const auto action = chooseAction(*state, entry.second.type, true);
if (action == Action::Send) { if (action == Action::Send) {
const auto id = entry.first; const auto id = entry.first;
const auto postponed = std::move(entry.second);
state->postponed.remove(id); state->postponed.remove(id);
state->sent.emplace(id, SentRequest{ state->sent.emplace(id, SentRequest{
entry.second.generator([=] { checkPostponed(history, id); }), postponed.generator([=] { checkPostponed(history, id); }),
entry.second.type postponed.type
}); });
if (base::take(state->thenRequestEntry)) { if (base::take(state->thenRequestEntry)) {
session().api().requestDialogEntry(history); session().api().requestDialogEntry(history);

View File

@ -33,10 +33,11 @@ public:
void unloadAll(); void unloadAll();
void clearAll(); void clearAll();
void readInboxTill( void readInbox(not_null<History*> history);
not_null<History*> history, void readInboxTill(not_null<HistoryItem*> item);
not_null<HistoryItem*> item);
void readInboxTill(not_null<History*> history, MsgId tillId); void readInboxTill(not_null<History*> history, MsgId tillId);
void readInboxOnNewMessage(not_null<HistoryItem*> item);
void readClientSideMessage(not_null<HistoryItem*> item);
void sendPendingReadInbox(not_null<History*> history); void sendPendingReadInbox(not_null<History*> history);
private: private:
@ -69,6 +70,7 @@ private:
bool thenRequestEntry = false; bool thenRequestEntry = false;
}; };
void readInboxTill(not_null<History*> history, MsgId tillId, bool force);
void sendReadRequests(); void sendReadRequests();
void sendReadRequest(not_null<History*> history, State &state); void sendReadRequest(not_null<History*> history, State &state);
[[nodiscard]] State *lookup(not_null<History*> history); [[nodiscard]] State *lookup(not_null<History*> history);

View File

@ -136,6 +136,9 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
_joinedMessage = nullptr; _joinedMessage = nullptr;
} }
item->removeMainView(); item->removeMainView();
if (_lastServerMessage == item) {
_lastServerMessage = std::nullopt;
}
if (lastMessage() == item) { if (lastMessage() == item) {
_lastMessage = std::nullopt; _lastMessage = std::nullopt;
if (loadedAtBottom()) { if (loadedAtBottom()) {
@ -1546,27 +1549,6 @@ void History::addToSharedMedia(
} }
} }
std::optional<int> History::countUnread(MsgId upTo) const {
if (!folderKnown() || !loadedAtBottom()) {
return std::nullopt;
}
auto result = 0;
for (auto i = blocks.cend(), e = blocks.cbegin(); i != e;) {
--i;
const auto &messages = (*i)->messages;
for (auto j = messages.cend(), en = messages.cbegin(); j != en;) {
--j;
const auto item = (*j)->data();
if (item->id > 0 && item->id <= upTo) {
return result;
} else if (!item->out() && item->unread()) {
++result;
}
}
}
return std::nullopt;
}
void History::calculateFirstUnreadMessage() { void History::calculateFirstUnreadMessage() {
if (_firstUnreadView || !_inboxReadBefore) { if (_firstUnreadView || !_inboxReadBefore) {
return; return;
@ -1603,64 +1585,12 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) {
} }
void History::readClientSideMessages() { void History::readClientSideMessages() {
auto unread = unreadCount(); auto &histories = owner().histories();
for (const auto item : _localMessages) { for (const auto item : _localMessages) {
if (!item->out() && item->unread()) { histories.readClientSideMessage(item);
item->markClientSideAsRead();
if (unread > 0) {
setUnreadCount(--unread);
}
}
} }
} }
void History::readInbox() {
if (_lastMessage) {
if (!*_lastMessage) {
owner().histories().readInboxTill(this, 0);
return;
} else if (IsServerMsgId((*_lastMessage)->id)) {
readInboxTill(*_lastMessage);
return;
}
}
if (loadedAtBottom()) {
const auto last = [&]() -> HistoryItem* {
for (const auto &block : ranges::view::reverse(blocks)) {
const auto &messages = block->messages;
for (const auto &item : ranges::view::reverse(messages)) {
if (IsServerMsgId(item->data()->id)) {
return item->data();
}
}
}
return nullptr;
}();
if (last) {
readInboxTill(last);
return;
} else if (loadedAtTop()) {
owner().histories().readInboxTill(this, 0);
return;
}
}
session().api().requestDialogEntry(this, [=] {
Expects(_lastMessage.has_value());
if (!*_lastMessage) {
owner().histories().readInboxTill(this, 0);
} else if (IsServerMsgId((*_lastMessage)->id)) {
readInboxTill(*_lastMessage);
} else {
Unexpected("Local _lastMessage after requestDialogEntry.");
}
});
}
void History::readInboxTill(not_null<HistoryItem*> item) {
owner().histories().readInboxTill(this, item);
}
bool History::unreadCountRefreshNeeded(MsgId readTillId) const { bool History::unreadCountRefreshNeeded(MsgId readTillId) const {
return !unreadCountKnown() return !unreadCountKnown()
|| ((readTillId + 1) > _inboxReadBefore.value_or(0)); || ((readTillId + 1) > _inboxReadBefore.value_or(0));
@ -1691,17 +1621,22 @@ std::optional<int> History::countStillUnreadLocal(MsgId readTillId) const {
} }
} }
} }
if (!loadedAtBottom() || minMsgId() > readTillId) { const auto minimalServerId = minMsgId();
if (!loadedAtBottom()
|| (!loadedAtTop() && !minimalServerId)
|| minimalServerId > readTillId) {
return std::nullopt; return std::nullopt;
} }
auto result = 0; auto result = 0;
for (const auto &block : blocks) { for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &message : block->messages) { for (const auto &message : ranges::view::reverse(block->messages)) {
const auto item = message->data(); const auto item = message->data();
if (!item->out() if (IsServerMsgId(item->id)) {
&& IsServerMsgId(item->id) if (item->id <= readTillId) {
&& item->id > readTillId) { return result;
++result; } else if (!item->out()) {
++result;
}
} }
} }
} }
@ -1734,7 +1669,7 @@ void History::inboxRead(MsgId upTo, std::optional<int> stillUnread) {
} }
if (stillUnread.has_value() && folderKnown()) { if (stillUnread.has_value() && folderKnown()) {
setUnreadCount(*stillUnread); setUnreadCount(*stillUnread);
} else if (const auto still = countUnread(upTo)) { } else if (const auto still = countStillUnreadLocal(upTo)) {
setUnreadCount(*still); setUnreadCount(*still);
} else { } else {
session().api().requestDialogEntry(this); session().api().requestDialogEntry(this);
@ -2370,6 +2305,7 @@ void History::clearSharedMedia() {
} }
void History::setLastServerMessage(HistoryItem *item) { void History::setLastServerMessage(HistoryItem *item) {
_lastServerMessage = item;
if (_lastMessage if (_lastMessage
&& *_lastMessage && *_lastMessage
&& !IsServerMsgId((*_lastMessage)->id) && !IsServerMsgId((*_lastMessage)->id)
@ -2384,6 +2320,9 @@ void History::setLastMessage(HistoryItem *item) {
return; return;
} }
_lastMessage = item; _lastMessage = item;
if (!item || IsServerMsgId(item->id)) {
_lastServerMessage = item;
}
if (peer->migrateTo()) { if (peer->migrateTo()) {
// We don't want to request last message for all deactivated chats. // We don't want to request last message for all deactivated chats.
// This is a heavy request for them, because we need to get last // This is a heavy request for them, because we need to get last
@ -2583,6 +2522,14 @@ bool History::lastMessageKnown() const {
return _lastMessage.has_value(); return _lastMessage.has_value();
} }
HistoryItem *History::lastServerMessage() const {
return _lastServerMessage.value_or(nullptr);
}
bool History::lastServerMessageKnown() const {
return _lastServerMessage.has_value();
}
void History::updateChatListExistence() { void History::updateChatListExistence() {
Entry::updateChatListExistence(); Entry::updateChatListExistence();
//if (const auto channel = peer->asChannel()) { // #feed //if (const auto channel = peer->asChannel()) { // #feed
@ -2691,7 +2638,9 @@ void History::applyDialog(
} }
void History::dialogEntryApplied() { void History::dialogEntryApplied() {
if (!lastMessageKnown()) { if (!lastServerMessageKnown()) {
setLastServerMessage(nullptr);
} else if (!lastMessageKnown()) {
setLastMessage(nullptr); setLastMessage(nullptr);
} }
if (peer->migrateTo()) { if (peer->migrateTo()) {

View File

@ -158,8 +158,6 @@ public:
void unregisterLocalMessage(not_null<HistoryItem*> item); void unregisterLocalMessage(not_null<HistoryItem*> item);
[[nodiscard]] HistoryItem *latestSendingMessage() const; [[nodiscard]] HistoryItem *latestSendingMessage() const;
void readInbox();
void readInboxTill(not_null<HistoryItem*> item);
[[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId); [[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId);
void applyInboxReadUpdate( void applyInboxReadUpdate(
FolderId folderId, FolderId folderId,
@ -203,7 +201,9 @@ public:
void getReadyFor(MsgId msgId); void getReadyFor(MsgId msgId);
[[nodiscard]] HistoryItem *lastMessage() const; [[nodiscard]] HistoryItem *lastMessage() const;
[[nodiscard]] HistoryItem *lastServerMessage() const;
[[nodiscard]] bool lastMessageKnown() const; [[nodiscard]] bool lastMessageKnown() const;
[[nodiscard]] bool lastServerMessageKnown() const;
void unknownMessageDeleted(MsgId messageId); void unknownMessageDeleted(MsgId messageId);
void applyDialogTopMessage(MsgId topMessageId); void applyDialogTopMessage(MsgId topMessageId);
void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data); void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data);
@ -478,7 +478,6 @@ private:
HistoryItem *lastAvailableMessage() const; HistoryItem *lastAvailableMessage() const;
void getNextFirstUnreadMessage(); void getNextFirstUnreadMessage();
bool nonEmptyCountMoreThan(int count) const; bool nonEmptyCountMoreThan(int count) const;
std::optional<int> countUnread(MsgId upTo) const;
// Creates if necessary a new block for adding item. // Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block. // Depending on isBuildingFrontBlock() gets front or back block.
@ -511,6 +510,7 @@ private:
std::optional<int> _unreadMentionsCount; std::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions; base::flat_set<MsgId> _unreadMentions;
std::optional<HistoryItem*> _lastMessage; std::optional<HistoryItem*> _lastMessage;
std::optional<HistoryItem*> _lastServerMessage;
base::flat_set<not_null<HistoryItem*>> _localMessages; base::flat_set<not_null<HistoryItem*>> _localMessages;
// This almost always is equal to _lastMessage. The only difference is // This almost always is equal to _lastMessage. The only difference is

View File

@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "facades.h" #include "facades.h"
#include "app.h" #include "app.h"
@ -704,7 +705,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p.restore(); p.restore();
if (readTill) { if (readTill) {
_history->readInboxTill(readTill); session().data().histories().readInboxTill(readTill);
} }
} }
@ -2059,7 +2060,7 @@ void HistoryInner::checkHistoryActivation() {
} }
} }
} }
_history->readInboxTill(view->data()); session().data().histories().readInboxTill(view->data());
} }
void HistoryInner::recountHistoryGeometry() { void HistoryInner::recountHistoryGeometry() {

View File

@ -2259,7 +2259,7 @@ void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
if (item->isUnreadMention() && !item->isUnreadMedia()) { if (item->isUnreadMention() && !item->isUnreadMedia()) {
session().api().markMediaRead(item); session().api().markMediaRead(item);
} }
_history->readInboxTill(item); session().data().histories().readInboxOnNewMessage(item);
// Also clear possible scheduled messages notifications. // Also clear possible scheduled messages notifications.
session().notifications().clearFromHistory(_history); session().notifications().clearFromHistory(_history);

View File

@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_histories.h"
#include "dialogs/dialogs_key.h" #include "dialogs/dialogs_key.h"
#include "boxes/peers/edit_peer_info_box.h" #include "boxes/peers/edit_peer_info_box.h"
#include "facades.h" #include "facades.h"
@ -303,7 +304,7 @@ void Filler::addToggleUnreadMark() {
const auto markAsRead = isUnread(peer); const auto markAsRead = isUnread(peer);
const auto handle = [&](not_null<History*> history) { const auto handle = [&](not_null<History*> history) {
if (markAsRead) { if (markAsRead) {
history->readInbox(); peer->session().data().histories().readInbox(history);
} else { } else {
peer->session().api().changeDialogUnreadMark( peer->session().api().changeDialogUnreadMark(
history, history,