summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-05-06 19:30:29 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-05-06 19:30:29 +0200
commit7dd333947711b9ebb54460066a25b07d155fa012 (patch)
treee7879c87bad2f2d23349de37a5c2a722b685bf1e /src
parentAllow picking multiple files to upload (diff)
downloadnheko-7dd333947711b9ebb54460066a25b07d155fa012.tar.xz
Sort rooms in completer by 'activity' and make tombstoned rooms italic
Diffstat (limited to 'src')
-rw-r--r--src/Cache.cpp44
-rw-r--r--src/CacheStructs.h4
-rw-r--r--src/Cache_p.h2
-rw-r--r--src/CompletionProxyModel.h12
-rw-r--r--src/RoomsModel.cpp22
-rw-r--r--src/RoomsModel.h1
6 files changed, 68 insertions, 17 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp
index b0b50004..1681f02c 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1792,7 +1792,9 @@ Cache::updateState(const std::string &room, const mtx::responses::StateEvents &s
     updatedInfo.topic      = getRoomTopic(txn, statesdb).toStdString();
     updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
     updatedInfo.version    = getRoomVersion(txn, statesdb).toStdString();
-    updatedInfo.is_space   = getRoomIsSpace(txn, statesdb);
+
+    updatedInfo.is_space      = getRoomIsSpace(txn, statesdb);
+    updatedInfo.is_tombstoned = getRoomIsTombstoned(txn, statesdb);
 
     roomsDb_.put(txn, room, nlohmann::json(updatedInfo).dump());
     updateSpaces(txn, {room}, {room});
@@ -2558,9 +2560,13 @@ Cache::roomNamesAndAliases()
                 alias = aliases->content.alias;
             }
 
-            result.push_back(RoomNameAlias{.id    = std::move(room_id_str),
-                                           .name  = std::move(info.name),
-                                           .alias = std::move(alias)});
+            result.push_back(RoomNameAlias{
+              .id              = std::move(room_id_str),
+              .name            = std::move(info.name),
+              .alias           = std::move(alias),
+              .recent_activity = info.approximate_last_modification_ts,
+              .is_tombstoned   = info.is_tombstoned,
+            });
         } catch (std::exception &e) {
             nhlog::db()->warn("Failed to add room {} to result: {}", room_id, e.what());
         }
@@ -3091,6 +3097,28 @@ Cache::getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb)
     return false;
 }
 
+bool
+Cache::getRoomIsTombstoned(lmdb::txn &txn, lmdb::dbi &statesdb)
+{
+    using namespace mtx::events;
+    using namespace mtx::events::state;
+
+    std::string_view event;
+    bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCreate), event);
+
+    if (res) {
+        try {
+            StateEvent<Tombstone> msg = nlohmann::json::parse(event).get<StateEvent<Tombstone>>();
+
+            return true;
+        } catch (const nlohmann::json::exception &e) {
+            nhlog::db()->warn("failed to parse m.room.tombstone event: {}", e.what());
+        }
+    }
+
+    return false;
+}
+
 QString
 Cache::getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
 {
@@ -5138,6 +5166,7 @@ to_json(nlohmann::json &j, const RoomInfo &info)
     j["version"]      = info.version;
     j["is_invite"]    = info.is_invite;
     j["is_space"]     = info.is_space;
+    j["tombst"]       = info.is_tombstoned;
     j["join_rule"]    = info.join_rule;
     j["guest_access"] = info.guest_access;
 
@@ -5161,8 +5190,11 @@ from_json(const nlohmann::json &j, RoomInfo &info)
     info.avatar_url = j.at("avatar_url").get<std::string>();
     info.version    = j.value(
       "version", QCoreApplication::translate("RoomInfo", "no version stored").toStdString());
-    info.is_invite    = j.at("is_invite").get<bool>();
-    info.is_space     = j.value("is_space", false);
+
+    info.is_invite     = j.at("is_invite").get<bool>();
+    info.is_space      = j.value("is_space", false);
+    info.is_tombstoned = j.value("tombst", false);
+
     info.join_rule    = j.at("join_rule").get<mtx::events::state::JoinRule>();
     info.guest_access = j.at("guest_access").get<bool>();
 
diff --git a/src/CacheStructs.h b/src/CacheStructs.h
index aa3e85d2..6dad4b19 100644
--- a/src/CacheStructs.h
+++ b/src/CacheStructs.h
@@ -81,6 +81,8 @@ struct RoomInfo
     bool is_invite = false;
     //! Wheter or not the room is a space
     bool is_space = false;
+    //! Wheter or not the room has a tombstone event
+    bool is_tombstoned = false;
     //! Total number of members in the room.
     size_t member_count = 0;
     //! Who can access to the room.
@@ -106,6 +108,8 @@ from_json(const nlohmann::json &j, RoomInfo &info);
 struct RoomNameAlias
 {
     std::string id, name, alias;
+    std::uint64_t recent_activity;
+    bool is_tombstoned;
 };
 
 //! Basic information per member.
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 7acb483f..7526d9b8 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -84,6 +84,8 @@ public:
     QString getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
     //! Retrieve if the room is a space
     bool getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb);
+    //! Retrieve if the room is tombstoned (closed or replaced by a different room)
+    bool getRoomIsTombstoned(lmdb::txn &txn, lmdb::dbi &statesdb);
 
     //! Get a specific state event
     template<typename T>
diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h
index e0f00788..a72b1d0a 100644
--- a/src/CompletionProxyModel.h
+++ b/src/CompletionProxyModel.h
@@ -8,6 +8,8 @@
 
 #include <QAbstractProxyModel>
 
+#include <algorithm>
+
 enum class ElementRank
 {
     first,
@@ -17,7 +19,7 @@ enum class ElementRank
 template<typename Key, typename Value>
 struct trie
 {
-    std::vector<Value> values;
+    std::vector<std::pair<ElementRank, Value>> values;
     std::map<Key, trie> next;
 
     template<ElementRank r>
@@ -29,9 +31,11 @@ struct trie
         }
 
         if constexpr (r == ElementRank::first) {
-            t->values.insert(t->values.begin(), v);
+            auto it =
+              std::ranges::upper_bound(t->values, r, {}, &std::pair<ElementRank, Value>::first);
+            t->values.emplace(it, r, v);
         } else if constexpr (r == ElementRank::second) {
-            t->values.push_back(v);
+            t->values.emplace_back(r, v);
         }
     }
 
@@ -45,7 +49,7 @@ struct trie
             if (ret.size() >= limit)
                 return ret;
             else
-                ret.push_back(v);
+                ret.push_back(v.second);
         }
 
         for (const auto &[k, t] : next) {
diff --git a/src/RoomsModel.cpp b/src/RoomsModel.cpp
index 43517b4b..32dce4f6 100644
--- a/src/RoomsModel.cpp
+++ b/src/RoomsModel.cpp
@@ -20,18 +20,24 @@ RoomsModel::RoomsModel(bool showOnlyRoomWithAliases, QObject *parent)
 
     if (showOnlyRoomWithAliases_)
         utils::erase_if(rooms, [](auto &r) { return r.alias.empty(); });
+
+    std::ranges::sort(rooms,
+                      [](auto &a, auto &b) { return a.recent_activity > b.recent_activity; });
 }
 
 QHash<int, QByteArray>
 RoomsModel::roleNames() const
 {
-    return {{CompletionModel::CompletionRole, "completionRole"},
-            {CompletionModel::SearchRole, "searchRole"},
-            {CompletionModel::SearchRole2, "searchRole2"},
-            {Roles::RoomAlias, "roomAlias"},
-            {Roles::AvatarUrl, "avatarUrl"},
-            {Roles::RoomID, "roomid"},
-            {Roles::RoomName, "roomName"}};
+    return {
+      {CompletionModel::CompletionRole, "completionRole"},
+      {CompletionModel::SearchRole, "searchRole"},
+      {CompletionModel::SearchRole2, "searchRole2"},
+      {Roles::RoomAlias, "roomAlias"},
+      {Roles::AvatarUrl, "avatarUrl"},
+      {Roles::RoomID, "roomid"},
+      {Roles::RoomName, "roomName"},
+      {Roles::IsTombstoned, "isTombstoned"},
+    };
 }
 
 QVariant
@@ -62,6 +68,8 @@ RoomsModel::data(const QModelIndex &index, int role) const
               cache::client()->singleRoomInfo(rooms[index.row()].id).avatar_url);
         case Roles::RoomID:
             return QString::fromStdString(rooms[index.row()].id).toHtmlEscaped();
+        case Roles::IsTombstoned:
+            return rooms[index.row()].is_tombstoned;
         }
     }
     return {};
diff --git a/src/RoomsModel.h b/src/RoomsModel.h
index 823b47e8..3e49ca87 100644
--- a/src/RoomsModel.h
+++ b/src/RoomsModel.h
@@ -18,6 +18,7 @@ public:
         RoomAlias,
         RoomID,
         RoomName,
+        IsTombstoned,
     };
 
     RoomsModel(bool showOnlyRoomWithAliases = false, QObject *parent = nullptr);