summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-02-10 01:03:20 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2021-02-10 01:03:20 +0100
commitbdb6e6b79e9beeaabfbde99cd760de77247d11a4 (patch)
tree99978bd9bd0222606ea3a9ba74233bc18efb44d2
parentAdd edit shortcuts and fix some focus stuff (diff)
downloadnheko-bdb6e6b79e9beeaabfbde99cd760de77247d11a4.tar.xz
Fix stuck notifications because of edits
Does not fix the read status yet, for that we need to compare read
receipts for all events after the last visible event.
Diffstat (limited to '')
-rw-r--r--src/Cache.cpp90
-rw-r--r--src/Cache.h6
-rw-r--r--src/Cache_p.h5
-rw-r--r--src/timeline/TimelineModel.cpp23
-rw-r--r--src/timeline/TimelineModel.h2
5 files changed, 121 insertions, 5 deletions
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 ((oldIndex > index || oldIndex == -1) && !currentId.startsWith("m")) {
-                readEvent(currentId.toStdString());
+        if (index != oldIndex)
+                emit currentIndexChanged(index);
+
+        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_;