diff --git a/src/Cache.cpp b/src/Cache.cpp
index 49861a9a..109fc60d 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1897,6 +1897,84 @@ Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id)
}
std::optional<uint64_t>
+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<uint64_t>();
+}
+
+std::optional<std::pair<uint64_t, std::string>>
+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<uint64_t>();
+ 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<std::string>();
+ 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<uint64_t>();
+ prevId = std::move(evId);
+ }
+ }
+
+ return std::pair{prevIdx, std::string(prevId)};
+}
+
+std::optional<uint64_t>
Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
@@ -4253,6 +4331,18 @@ readReceipts(const QString &event_id, const QString &room_id)
return instance_->readReceipts(event_id, room_id);
}
+std::optional<uint64_t>
+getEventIndex(const std::string &room_id, std::string_view event_id)
+{
+ return instance_->getEventIndex(room_id, event_id);
+}
+
+std::optional<std::pair<uint64_t, std::string>>
+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<uint64_t, std::string, std::greater<uint64_t>
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<uint64_t>
+getEventIndex(const std::string &room_id, std::string_view event_id);
+std::optional<std::pair<uint64_t, std::string>>
+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<TimelineRange> getTimelineRange(const std::string &room_id);
std::optional<uint64_t> getTimelineIndex(const std::string &room_id,
std::string_view event_id);
+ std::optional<uint64_t> getEventIndex(const std::string &room_id,
+ std::string_view event_id);
+ std::optional<std::pair<uint64_t, std::string>> lastInvisibleEventAfter(
+ const std::string &room_id,
+ std::string_view event_id);
std::optional<std::string> getTimelineEventId(const std::string &room_id, uint64_t index);
std::optional<uint64_t> 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<QString> typingUsers_;
|