diff --git a/src/Cache.cpp b/src/Cache.cpp index 49861a9a..109fc60d 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1896,6 +1896,84 @@ Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id) return *val.data(); } +std::optional +Cache::getEventIndex(const std::string &room_id, std::string_view event_id) +{ + if (event_id.empty()) + return {}; + + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::dbi orderDb{0}; + try { + orderDb = getEventToOrderDb(txn, room_id); + } catch (lmdb::runtime_error &e) { + nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})", + room_id, + e.what()); + return {}; + } + + lmdb::val indexVal{event_id.data(), event_id.size()}, val; + + bool success = lmdb::dbi_get(txn, orderDb, indexVal, val); + if (!success) { + nhlog::db()->critical("Could not find event id: {}", event_id); + return {}; + } + + return *val.data(); +} + +std::optional> +Cache::lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id) +{ + if (event_id.empty()) + return {}; + + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::dbi orderDb{0}; + lmdb::dbi eventOrderDb{0}; + lmdb::dbi timelineDb{0}; + try { + orderDb = getEventToOrderDb(txn, room_id); + eventOrderDb = getEventOrderDb(txn, room_id); + timelineDb = getMessageToOrderDb(txn, room_id); + } catch (lmdb::runtime_error &e) { + nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})", + room_id, + e.what()); + return {}; + } + + lmdb::val eventIdVal{event_id.data(), event_id.size()}, indexVal; + + bool success = lmdb::dbi_get(txn, orderDb, eventIdVal, indexVal); + if (!success) { + return {}; + } + uint64_t prevIdx = *indexVal.data(); + std::string prevId{eventIdVal.data(), eventIdVal.size()}; + + auto cursor = lmdb::cursor::open(txn, eventOrderDb); + cursor.get(indexVal, MDB_SET); + while (cursor.get(indexVal, eventIdVal, MDB_NEXT)) { + std::string evId = + json::parse(std::string_view(eventIdVal.data(), eventIdVal.size()))["event_id"] + .get(); + lmdb::val temp; + if (lmdb::dbi_get(txn, timelineDb, lmdb::val(evId.data(), evId.size()), temp)) { + return std::pair{prevIdx, std::string(prevId)}; + } else { + prevIdx = *indexVal.data(); + prevId = std::move(evId); + } + } + + return std::pair{prevIdx, std::string(prevId)}; +} + std::optional Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id) { @@ -4253,6 +4331,18 @@ readReceipts(const QString &event_id, const QString &room_id) return instance_->readReceipts(event_id, room_id); } +std::optional +getEventIndex(const std::string &room_id, std::string_view event_id) +{ + return instance_->getEventIndex(room_id, event_id); +} + +std::optional> +lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id) +{ + return instance_->lastInvisibleEventAfter(room_id, event_id); +} + QByteArray image(const QString &url) { diff --git a/src/Cache.h b/src/Cache.h index 91956725..e60fc970 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -168,6 +168,12 @@ using UserReceipts = std::multimap UserReceipts readReceipts(const QString &event_id, const QString &room_id); +//! get index of the event in the event db, not representing the visual index +std::optional +getEventIndex(const std::string &room_id, std::string_view event_id); +std::optional> +lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id); + QByteArray image(const QString &url); QByteArray diff --git a/src/Cache_p.h b/src/Cache_p.h index c96a3f30..431e7bc3 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -204,6 +204,11 @@ public: std::optional getTimelineRange(const std::string &room_id); std::optional getTimelineIndex(const std::string &room_id, std::string_view event_id); + std::optional getEventIndex(const std::string &room_id, + std::string_view event_id); + std::optional> lastInvisibleEventAfter( + const std::string &room_id, + std::string_view event_id); std::optional getTimelineEventId(const std::string &room_id, uint64_t index); std::optional getArrivalIndex(const std::string &room_id, std::string_view event_id); diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index de43d5ea..1163d931 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -740,10 +740,25 @@ TimelineModel::setCurrentIndex(int index) auto oldIndex = idToIndex(currentId); currentId = indexToId(index); - emit currentIndexChanged(index); + if (index != oldIndex) + emit currentIndexChanged(index); - if ((oldIndex > index || oldIndex == -1) && !currentId.startsWith("m")) { - readEvent(currentId.toStdString()); + if (!currentId.startsWith("m")) { + auto oldReadIndex = + cache::getEventIndex(roomId().toStdString(), currentReadId.toStdString()); + auto nextEventIndexAndId = + cache::lastInvisibleEventAfter(roomId().toStdString(), currentId.toStdString()); + + if (nextEventIndexAndId && + (!oldReadIndex || *oldReadIndex < nextEventIndexAndId->first)) { + readEvent(nextEventIndexAndId->second); + currentReadId = QString::fromStdString(nextEventIndexAndId->second); + + nhlog::net()->info("Marked as read {}, index {}, oldReadIndex {}", + nextEventIndexAndId->second, + nextEventIndexAndId->first, + *oldReadIndex); + } } } diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 0aec27a1..017b6589 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -329,7 +329,7 @@ private: bool decryptDescription = true; bool m_paginationInProgress = false; - QString currentId; + QString currentId, currentReadId; QString reply_, edit_; std::vector typingUsers_;