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_user.h"
#include "data/data_cloud_themes.h"
#include "data/data_histories.h"
#include "dialogs/dialogs_key.h"
#include "core/core_cloud_password.h"
#include "core/application.h"
@ -4432,7 +4433,7 @@ void ApiWrap::userPhotosDone(
//}
void ApiWrap::sendAction(const SendAction &action) {
action.history->readInbox();
session().data().histories().readInbox(action.history);
action.history->getReadyFor(ShowAtTheEndMsgId);
_sendActions.fire_copy(action);
}
@ -4459,7 +4460,7 @@ void ApiWrap::forwardMessages(
const auto history = action.history;
const auto peer = history->peer;
history->readInbox();
session().data().histories().readInbox(history);
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = action.options.silent

View File

@ -63,10 +63,32 @@ void Histories::clearAll() {
_map.clear();
}
void Histories::readInboxTill(
not_null<History*> history,
not_null<HistoryItem*> item) {
void Histories::readInbox(not_null<History*> history) {
if (history->lastServerMessageKnown()) {
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)) {
readClientSideMessage(item);
auto view = item->mainView();
if (!view) {
return;
@ -102,15 +124,23 @@ void Histories::readInboxTill(
}
void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
if (!history->readInboxTillNeedsRequest(tillId)) {
return;
}
const auto maybeState = lookup(history);
if (maybeState && maybeState->readTill >= tillId) {
readInboxTill(history, tillId, false);
}
void Histories::readInboxTill(
not_null<History*> history,
MsgId tillId,
bool force) {
if (!history->readInboxTillNeedsRequest(tillId) && !force) {
return;
} else if (!force) {
const auto maybeState = lookup(history);
if (maybeState && maybeState->readTill >= tillId) {
return;
}
}
const auto stillUnread = history->countStillUnreadLocal(tillId);
if (stillUnread
if (!force
&& stillUnread
&& history->unreadCountKnown()
&& *stillUnread == history->unreadCount()) {
history->setInboxReadTill(tillId);
@ -119,10 +149,12 @@ void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
auto &state = _states[history];
const auto wasReadTill = state.readTill;
state.readTill = tillId;
if (!stillUnread) {
if (force || !stillUnread || !*stillUnread) {
state.readWhen = 0;
sendReadRequests();
return;
if (!stillUnread) {
return;
}
} else if (!wasReadTill) {
state.readWhen = crl::now() + kReadRequestTimeout;
if (!_readRequestsTimer.isActive()) {
@ -134,6 +166,25 @@ void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
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) {
if (const auto state = lookup(history)) {
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);
if (action == Action::Send) {
const auto id = entry.first;
const auto postponed = std::move(entry.second);
state->postponed.remove(id);
state->sent.emplace(id, SentRequest{
entry.second.generator([=] { checkPostponed(history, id); }),
entry.second.type
postponed.generator([=] { checkPostponed(history, id); }),
postponed.type
});
if (base::take(state->thenRequestEntry)) {
session().api().requestDialogEntry(history);

View File

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

View File

@ -136,6 +136,9 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
_joinedMessage = nullptr;
}
item->removeMainView();
if (_lastServerMessage == item) {
_lastServerMessage = std::nullopt;
}
if (lastMessage() == item) {
_lastMessage = std::nullopt;
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() {
if (_firstUnreadView || !_inboxReadBefore) {
return;
@ -1603,64 +1585,12 @@ bool History::readInboxTillNeedsRequest(MsgId tillId) {
}
void History::readClientSideMessages() {
auto unread = unreadCount();
auto &histories = owner().histories();
for (const auto item : _localMessages) {
if (!item->out() && item->unread()) {
item->markClientSideAsRead();
if (unread > 0) {
setUnreadCount(--unread);
}
}
histories.readClientSideMessage(item);
}
}
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 {
return !unreadCountKnown()
|| ((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;
}
auto result = 0;
for (const auto &block : blocks) {
for (const auto &message : block->messages) {
for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &message : ranges::view::reverse(block->messages)) {
const auto item = message->data();
if (!item->out()
&& IsServerMsgId(item->id)
&& item->id > readTillId) {
++result;
if (IsServerMsgId(item->id)) {
if (item->id <= readTillId) {
return result;
} else if (!item->out()) {
++result;
}
}
}
}
@ -1734,7 +1669,7 @@ void History::inboxRead(MsgId upTo, std::optional<int> stillUnread) {
}
if (stillUnread.has_value() && folderKnown()) {
setUnreadCount(*stillUnread);
} else if (const auto still = countUnread(upTo)) {
} else if (const auto still = countStillUnreadLocal(upTo)) {
setUnreadCount(*still);
} else {
session().api().requestDialogEntry(this);
@ -2370,6 +2305,7 @@ void History::clearSharedMedia() {
}
void History::setLastServerMessage(HistoryItem *item) {
_lastServerMessage = item;
if (_lastMessage
&& *_lastMessage
&& !IsServerMsgId((*_lastMessage)->id)
@ -2384,6 +2320,9 @@ void History::setLastMessage(HistoryItem *item) {
return;
}
_lastMessage = item;
if (!item || IsServerMsgId(item->id)) {
_lastServerMessage = item;
}
if (peer->migrateTo()) {
// 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
@ -2583,6 +2522,14 @@ bool History::lastMessageKnown() const {
return _lastMessage.has_value();
}
HistoryItem *History::lastServerMessage() const {
return _lastServerMessage.value_or(nullptr);
}
bool History::lastServerMessageKnown() const {
return _lastServerMessage.has_value();
}
void History::updateChatListExistence() {
Entry::updateChatListExistence();
//if (const auto channel = peer->asChannel()) { // #feed
@ -2691,7 +2638,9 @@ void History::applyDialog(
}
void History::dialogEntryApplied() {
if (!lastMessageKnown()) {
if (!lastServerMessageKnown()) {
setLastServerMessage(nullptr);
} else if (!lastMessageKnown()) {
setLastMessage(nullptr);
}
if (peer->migrateTo()) {

View File

@ -158,8 +158,6 @@ public:
void unregisterLocalMessage(not_null<HistoryItem*> item);
[[nodiscard]] HistoryItem *latestSendingMessage() const;
void readInbox();
void readInboxTill(not_null<HistoryItem*> item);
[[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId);
void applyInboxReadUpdate(
FolderId folderId,
@ -203,7 +201,9 @@ public:
void getReadyFor(MsgId msgId);
[[nodiscard]] HistoryItem *lastMessage() const;
[[nodiscard]] HistoryItem *lastServerMessage() const;
[[nodiscard]] bool lastMessageKnown() const;
[[nodiscard]] bool lastServerMessageKnown() const;
void unknownMessageDeleted(MsgId messageId);
void applyDialogTopMessage(MsgId topMessageId);
void applyDialog(Data::Folder *requestFolder, const MTPDdialog &data);
@ -478,7 +478,6 @@ private:
HistoryItem *lastAvailableMessage() const;
void getNextFirstUnreadMessage();
bool nonEmptyCountMoreThan(int count) const;
std::optional<int> countUnread(MsgId upTo) const;
// Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block.
@ -511,6 +510,7 @@ private:
std::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions;
std::optional<HistoryItem*> _lastMessage;
std::optional<HistoryItem*> _lastServerMessage;
base::flat_set<not_null<HistoryItem*>> _localMessages;
// 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_user.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "facades.h"
#include "app.h"
@ -704,7 +705,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p.restore();
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() {

View File

@ -2259,7 +2259,7 @@ void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
if (item->isUnreadMention() && !item->isUnreadMedia()) {
session().api().markMediaRead(item);
}
_history->readInboxTill(item);
session().data().histories().readInboxOnNewMessage(item);
// Also clear possible scheduled messages notifications.
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_user.h"
#include "data/data_scheduled_messages.h"
#include "data/data_histories.h"
#include "dialogs/dialogs_key.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "facades.h"
@ -303,7 +304,7 @@ void Filler::addToggleUnreadMark() {
const auto markAsRead = isUnread(peer);
const auto handle = [&](not_null<History*> history) {
if (markAsRead) {
history->readInbox();
peer->session().data().histories().readInbox(history);
} else {
peer->session().api().changeDialogUnreadMark(
history,