diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2020-07-19 12:22:54 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2020-07-19 12:22:54 +0200 |
commit | 6f2bc908badc207754ff55d543d41d9e2b847c97 (patch) | |
tree | 179012d3d482aa539462bf203651d3df04022df4 /src | |
parent | Close cursor we don't need and where we overwrite the contents (diff) | |
download | nheko-6f2bc908badc207754ff55d543d41d9e2b847c97.tar.xz |
Fix reaction display
Diffstat (limited to 'src')
-rw-r--r-- | src/Cache.cpp | 35 | ||||
-rw-r--r-- | src/Cache_p.h | 3 | ||||
-rw-r--r-- | src/timeline/EventStore.cpp | 70 | ||||
-rw-r--r-- | src/timeline/EventStore.h | 5 | ||||
-rw-r--r-- | src/timeline/Reaction.cpp | 1 | ||||
-rw-r--r-- | src/timeline/Reaction.h | 24 | ||||
-rw-r--r-- | src/timeline/ReactionsModel.cpp | 98 | ||||
-rw-r--r-- | src/timeline/ReactionsModel.h | 41 | ||||
-rw-r--r-- | src/timeline/TimelineModel.cpp | 3 | ||||
-rw-r--r-- | src/timeline/TimelineModel.h | 1 |
10 files changed, 140 insertions, 141 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp index 9464a546..0307bee1 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1353,6 +1353,37 @@ Cache::storeEvent(const std::string &room_id, txn.commit(); } +std::vector<std::string> +Cache::relatedEvents(const std::string &room_id, const std::string &event_id) +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + auto relationsDb = getRelationsDb(txn, room_id); + + std::vector<std::string> related_ids; + + auto related_cursor = lmdb::cursor::open(txn, relationsDb); + lmdb::val related_to = event_id, related_event; + bool first = true; + + try { + if (!related_cursor.get(related_to, related_event, MDB_SET)) + return {}; + + while (related_cursor.get( + related_to, related_event, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) { + first = false; + if (event_id != std::string_view(related_to.data(), related_to.size())) + break; + + related_ids.emplace_back(related_event.data(), related_event.size()); + } + } catch (const lmdb::error &e) { + nhlog::db()->error("related events error: {}", e.what()); + } + + return related_ids; +} + QMap<QString, RoomInfo> Cache::roomInfo(bool withInvites) { @@ -2354,6 +2385,10 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message std::string event_id_val; for (const auto &e : res.chunk) { + if (std::holds_alternative< + mtx::events::RedactionEvent<mtx::events::msg::Redaction>>(e)) + continue; + auto event = mtx::accessors::serialize_event(e); event_id_val = event["event_id"].get<std::string>(); lmdb::val event_id = event_id_val; diff --git a/src/Cache_p.h b/src/Cache_p.h index 88308e45..61d91b0c 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -188,6 +188,9 @@ public: void storeEvent(const std::string &room_id, const std::string &event_id, const mtx::events::collections::TimelineEvent &event); + std::vector<std::string> relatedEvents(const std::string &room_id, + const std::string &event_id); + struct TimelineRange { uint64_t first, last; diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 80e8d474..0bd7a97e 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -3,12 +3,15 @@ #include <QThread> #include <QTimer> +#include "Cache.h" #include "Cache_p.h" #include "EventAccessors.h" #include "Logging.h" #include "MatrixClient.h" #include "Olm.h" +Q_DECLARE_METATYPE(Reaction) + QCache<EventStore::IdIndex, mtx::events::collections::TimelineEvents> EventStore::decryptedEvents_{ 1000}; QCache<EventStore::IdIndex, mtx::events::collections::TimelineEvents> EventStore::events_by_id_{ @@ -18,6 +21,9 @@ QCache<EventStore::Index, mtx::events::collections::TimelineEvents> EventStore:: EventStore::EventStore(std::string room_id, QObject *) : room_id_(std::move(room_id)) { + static auto reactionType = qRegisterMetaType<Reaction>(); + (void)reactionType; + auto range = cache::client()->getTimelineRange(room_id_); if (range) { @@ -223,6 +229,70 @@ EventStore::handleSync(const mtx::responses::Timeline &events) } } +QVariantList +EventStore::reactions(const std::string &event_id) +{ + auto event_ids = cache::client()->relatedEvents(room_id_, event_id); + + struct TempReaction + { + int count = 0; + std::vector<std::string> users; + std::string reactedBySelf; + }; + std::map<std::string, TempReaction> aggregation; + std::vector<Reaction> reactions; + + auto self = http::client()->user_id().to_string(); + for (const auto &id : event_ids) { + auto related_event = event(id, event_id); + if (!related_event) + continue; + + if (auto reaction = std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>( + related_event)) { + auto &agg = aggregation[reaction->content.relates_to.key]; + + if (agg.count == 0) { + Reaction temp{}; + temp.key_ = + QString::fromStdString(reaction->content.relates_to.key); + reactions.push_back(temp); + } + + agg.count++; + agg.users.push_back(cache::displayName(room_id_, reaction->sender)); + if (reaction->sender == self) + agg.reactedBySelf = reaction->event_id; + } + } + + QVariantList temp; + for (auto &reaction : reactions) { + const auto &agg = aggregation[reaction.key_.toStdString()]; + reaction.count_ = agg.count; + reaction.selfReactedEvent_ = QString::fromStdString(agg.reactedBySelf); + + bool first = true; + for (const auto &user : agg.users) { + if (first) + first = false; + else + reaction.users_ += ", "; + + reaction.users_ += QString::fromStdString(user); + } + + nhlog::db()->debug("key: {}, count: {}, users: {}", + reaction.key_.toStdString(), + reaction.count_, + reaction.users_.toStdString()); + temp.append(QVariant::fromValue(reaction)); + } + + return temp; +} + mtx::events::collections::TimelineEvents * EventStore::event(int idx, bool decrypt) { diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h index 3a78cba8..5a792040 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h @@ -5,12 +5,15 @@ #include <QCache> #include <QObject> +#include <QVariant> #include <qhashfunctions.h> #include <mtx/events/collections.hpp> #include <mtx/responses/messages.hpp> #include <mtx/responses/sync.hpp> +#include "Reaction.h" + class EventStore : public QObject { Q_OBJECT @@ -65,6 +68,8 @@ public: // always returns a proper event as long as the idx is valid mtx::events::collections::TimelineEvents *event(int idx, bool decrypt = true); + QVariantList reactions(const std::string &event_id); + int size() const { return last != std::numeric_limits<uint64_t>::max() diff --git a/src/timeline/Reaction.cpp b/src/timeline/Reaction.cpp new file mode 100644 index 00000000..343c4649 --- /dev/null +++ b/src/timeline/Reaction.cpp @@ -0,0 +1 @@ +#include "Reaction.h" diff --git a/src/timeline/Reaction.h b/src/timeline/Reaction.h new file mode 100644 index 00000000..5f122e0a --- /dev/null +++ b/src/timeline/Reaction.h @@ -0,0 +1,24 @@ +#pragma once + +#include <QObject> +#include <QString> + +struct Reaction +{ + Q_GADGET + Q_PROPERTY(QString key READ key) + Q_PROPERTY(QString users READ users) + Q_PROPERTY(QString selfReactedEvent READ selfReactedEvent) + Q_PROPERTY(int count READ count) + +public: + QString key() const { return key_; } + QString users() const { return users_; } + QString selfReactedEvent() const { return selfReactedEvent_; } + int count() const { return count_; } + + QString key_; + QString users_; + QString selfReactedEvent_; + int count_; +}; diff --git a/src/timeline/ReactionsModel.cpp b/src/timeline/ReactionsModel.cpp deleted file mode 100644 index 1200e2ba..00000000 --- a/src/timeline/ReactionsModel.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "ReactionsModel.h" - -#include <Cache.h> -#include <MatrixClient.h> - -QHash<int, QByteArray> -ReactionsModel::roleNames() const -{ - return { - {Key, "key"}, - {Count, "counter"}, - {Users, "users"}, - {SelfReactedEvent, "selfReactedEvent"}, - }; -} - -int -ReactionsModel::rowCount(const QModelIndex &) const -{ - return static_cast<int>(reactions.size()); -} - -QVariant -ReactionsModel::data(const QModelIndex &index, int role) const -{ - const int i = index.row(); - if (i < 0 || i >= static_cast<int>(reactions.size())) - return {}; - - switch (role) { - case Key: - return QString::fromStdString(reactions[i].key); - case Count: - return static_cast<int>(reactions[i].reactions.size()); - case Users: { - QString users; - bool first = true; - for (const auto &reaction : reactions[i].reactions) { - if (!first) - users += ", "; - else - first = false; - users += QString::fromStdString( - cache::displayName(room_id_, reaction.second.sender)); - } - return users; - } - case SelfReactedEvent: - for (const auto &reaction : reactions[i].reactions) - if (reaction.second.sender == http::client()->user_id().to_string()) - return QString::fromStdString(reaction.second.event_id); - return QStringLiteral(""); - default: - return {}; - } -} - -void -ReactionsModel::addReaction(const std::string &room_id, - const mtx::events::RoomEvent<mtx::events::msg::Reaction> &reaction) -{ - room_id_ = room_id; - - int idx = 0; - for (auto &storedReactions : reactions) { - if (storedReactions.key == reaction.content.relates_to.key) { - storedReactions.reactions[reaction.event_id] = reaction; - emit dataChanged(index(idx, 0), index(idx, 0)); - return; - } - idx++; - } - - beginInsertRows(QModelIndex(), idx, idx); - reactions.push_back( - KeyReaction{reaction.content.relates_to.key, {{reaction.event_id, reaction}}}); - endInsertRows(); -} - -void -ReactionsModel::removeReaction(const mtx::events::RoomEvent<mtx::events::msg::Reaction> &reaction) -{ - int idx = 0; - for (auto &storedReactions : reactions) { - if (storedReactions.key == reaction.content.relates_to.key) { - storedReactions.reactions.erase(reaction.event_id); - - if (storedReactions.reactions.size() == 0) { - beginRemoveRows(QModelIndex(), idx, idx); - reactions.erase(reactions.begin() + idx); - endRemoveRows(); - } else - emit dataChanged(index(idx, 0), index(idx, 0)); - return; - } - idx++; - } -} diff --git a/src/timeline/ReactionsModel.h b/src/timeline/ReactionsModel.h deleted file mode 100644 index c839afc8..00000000 --- a/src/timeline/ReactionsModel.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <QAbstractListModel> -#include <QHash> - -#include <utility> -#include <vector> - -#include <mtx/events/collections.hpp> - -class ReactionsModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit ReactionsModel(QObject *parent = nullptr) { Q_UNUSED(parent); } - enum Roles - { - Key, - Count, - Users, - SelfReactedEvent, - }; - - QHash<int, QByteArray> roleNames() const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - -public slots: - void addReaction(const std::string &room_id, - const mtx::events::RoomEvent<mtx::events::msg::Reaction> &reaction); - void removeReaction(const mtx::events::RoomEvent<mtx::events::msg::Reaction> &reaction); - -private: - struct KeyReaction - { - std::string key; - std::map<std::string, mtx::events::RoomEvent<mtx::events::msg::Reaction>> reactions; - }; - std::string room_id_; - std::vector<KeyReaction> reactions; -}; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 470e3988..85d2eb4e 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -366,7 +366,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r case ReplyTo: return QVariant(QString::fromStdString(in_reply_to_event(event))); case Reactions: { - return {}; + auto id = event_id(event); + return QVariant::fromValue(events.reactions(id)); } case RoomId: return QVariant(room_id_); diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 9f9717df..cbe88fd2 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -10,7 +10,6 @@ #include "CacheCryptoStructs.h" #include "EventStore.h" -#include "ReactionsModel.h" namespace mtx::http { using RequestErr = const std::optional<mtx::http::ClientError> &; |