From 7dd333947711b9ebb54460066a25b07d155fa012 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 6 May 2023 19:30:29 +0200 Subject: [PATCH] Sort rooms in completer by 'activity' and make tombstoned rooms italic --- resources/qml/Completer.qml | 2 ++ src/Cache.cpp | 44 ++++++++++++++++++++++++++++++++----- src/CacheStructs.h | 4 ++++ src/Cache_p.h | 2 ++ src/CompletionProxyModel.h | 12 ++++++---- src/RoomsModel.cpp | 22 +++++++++++++------ src/RoomsModel.h | 1 + 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 9700f843..cc1047a0 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -292,6 +292,7 @@ Control { text: model.roomName font.pixelSize: popup.avatarHeight * 0.5 color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + font.italic: model.isTombstoned textFormat: Text.RichText } @@ -320,6 +321,7 @@ Control { Label { text: model.roomName color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + font.italic: model.isTombstoned textFormat: Text.RichText } 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 msg = nlohmann::json::parse(event).get>(); + + 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(); info.version = j.value( "version", QCoreApplication::translate("RoomInfo", "no version stored").toStdString()); - info.is_invite = j.at("is_invite").get(); - info.is_space = j.value("is_space", false); + + info.is_invite = j.at("is_invite").get(); + info.is_space = j.value("is_space", false); + info.is_tombstoned = j.value("tombst", false); + info.join_rule = j.at("join_rule").get(); info.guest_access = j.at("guest_access").get(); 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 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 +#include + enum class ElementRank { first, @@ -17,7 +19,7 @@ enum class ElementRank template struct trie { - std::vector values; + std::vector> values; std::map next; template @@ -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::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 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);