diff --git a/src/Cache.cpp b/src/Cache.cpp
index b197353e..eec5b79f 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -3897,53 +3897,26 @@ Cache::avatarUrl(const QString &room_id, const QString &user_id)
return QString();
}
-mtx::presence::PresenceState
-Cache::presenceState(const std::string &user_id)
+mtx::events::presence::Presence
+Cache::presence(const std::string &user_id)
{
if (user_id.empty())
return {};
std::string_view presenceVal;
- auto txn = lmdb::txn::begin(env_);
- auto db = getPresenceDb(txn);
- auto res = db.get(txn, user_id, presenceVal);
-
- mtx::presence::PresenceState state = mtx::presence::offline;
-
- if (res) {
- mtx::events::presence::Presence presence =
- json::parse(std::string_view(presenceVal.data(), presenceVal.size()));
- state = presence.presence;
- }
-
- txn.commit();
-
- return state;
-}
-
-std::string
-Cache::statusMessage(const std::string &user_id)
-{
- if (user_id.empty())
- return {};
-
- std::string_view presenceVal;
-
- auto txn = lmdb::txn::begin(env_);
+ auto txn = ro_txn(env_);
auto db = getPresenceDb(txn);
auto res = db.get(txn, user_id, presenceVal);
- std::string status_msg;
+ mtx::events::presence::Presence presence_{};
+ presence_.presence = mtx::presence::PresenceState::offline;
if (res) {
- mtx::events::presence::Presence presence = json::parse(presenceVal);
- status_msg = presence.status_msg;
+ presence_ = json::parse(std::string_view(presenceVal.data(), presenceVal.size()));
}
- txn.commit();
-
- return status_msg;
+ return presence_;
}
void
@@ -4747,17 +4720,12 @@ avatarUrl(const QString &room_id, const QString &user_id)
return instance_->avatarUrl(room_id, user_id);
}
-mtx::presence::PresenceState
-presenceState(const std::string &user_id)
+mtx::events::presence::Presence
+presence(const std::string &user_id)
{
if (!instance_)
return {};
- return instance_->presenceState(user_id);
-}
-std::string
-statusMessage(const std::string &user_id)
-{
- return instance_->statusMessage(user_id);
+ return instance_->presence(user_id);
}
// user cache stores user keys
diff --git a/src/Cache.h b/src/Cache.h
index f8626430..4a5175f3 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -38,10 +38,8 @@ QString
avatarUrl(const QString &room_id, const QString &user_id);
// presence
-mtx::presence::PresenceState
-presenceState(const std::string &user_id);
-std::string
-statusMessage(const std::string &user_id);
+mtx::events::presence::Presence
+presence(const std::string &user_id);
// user cache stores user keys
std::optional<UserKeyCache>
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 6a6b4e0c..a9f1a4e0 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -43,8 +43,7 @@ public:
QString avatarUrl(const QString &room_id, const QString &user_id);
// presence
- mtx::presence::PresenceState presenceState(const std::string &user_id);
- std::string statusMessage(const std::string &user_id);
+ mtx::events::presence::Presence presence(const std::string &user_id);
// user cache stores user keys
std::map<std::string, std::optional<UserKeyCache>>
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 46c8a9f9..139f935c 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -877,7 +877,7 @@ ChatPage::receivedSessionKey(const std::string &room_id, const std::string &sess
QString
ChatPage::status() const
{
- return QString::fromStdString(cache::statusMessage(utils::localUser().toStdString()));
+ return QString::fromStdString(cache::presence(utils::localUser().toStdString()).status_msg);
}
void
diff --git a/src/timeline/PresenceEmitter.cpp b/src/timeline/PresenceEmitter.cpp
new file mode 100644
index 00000000..c052bf43
--- /dev/null
+++ b/src/timeline/PresenceEmitter.cpp
@@ -0,0 +1,73 @@
+#include "PresenceEmitter.h"
+
+#include <QCache>
+#include <Utils.h>
+
+#include "Cache.h"
+
+namespace {
+struct CacheEntry
+{
+ QString status;
+ mtx::presence::PresenceState state;
+};
+}
+
+static QCache<QString, CacheEntry> presences;
+
+static QString
+presenceToStr(mtx::presence::PresenceState state)
+{
+ switch (state) {
+ case mtx::presence::PresenceState::offline:
+ return QStringLiteral("offline");
+ case mtx::presence::PresenceState::unavailable:
+ return QStringLiteral("unavailable");
+ case mtx::presence::PresenceState::online:
+ default:
+ return QStringLiteral("online");
+ }
+}
+
+static CacheEntry *
+pullPresence(const QString &id)
+{
+ auto p = cache::presence(id.toStdString());
+ auto c = new CacheEntry{
+ utils::replaceEmoji(QString::fromStdString(p.status_msg).toHtmlEscaped()), p.presence};
+ presences.insert(id, c);
+ return c;
+}
+
+void
+PresenceEmitter::sync(
+ const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences_)
+{
+ for (const auto &p : presences_) {
+ auto id = QString::fromStdString(p.sender);
+ presences.remove(id);
+ emit presenceChanged(std::move(id));
+ }
+}
+
+QString
+PresenceEmitter::userPresence(QString id) const
+{
+ if (id.isEmpty())
+ return {};
+ else if (auto p = presences[id])
+ return presenceToStr(p->state);
+ else
+ return presenceToStr(pullPresence(id)->state);
+}
+
+QString
+PresenceEmitter::userStatus(QString id) const
+{
+ if (id.isEmpty())
+ return {};
+ else if (auto p = presences[id])
+ return p->status;
+ else
+ return pullPresence(id)->status;
+}
diff --git a/src/timeline/PresenceEmitter.h b/src/timeline/PresenceEmitter.h
new file mode 100644
index 00000000..bf1a9458
--- /dev/null
+++ b/src/timeline/PresenceEmitter.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <QObject>
+
+#include <vector>
+
+#include <mtx/events.hpp>
+#include <mtx/events/presence.hpp>
+
+class PresenceEmitter : public QObject
+{
+ Q_OBJECT
+
+public:
+ PresenceEmitter(QObject *p = nullptr)
+ : QObject(p)
+ {}
+
+ void sync(const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences);
+
+ Q_INVOKABLE QString userPresence(QString id) const;
+ Q_INVOKABLE QString userStatus(QString id) const;
+
+signals:
+ void presenceChanged(QString userid);
+};
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 70a1510a..bab093b0 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -124,29 +124,6 @@ TimelineViewManager::userColor(QString id, QColor background)
return userColors.value(idx);
}
-QString
-TimelineViewManager::userPresence(QString id) const
-{
- if (id.isEmpty())
- return {};
- else
- switch (cache::presenceState(id.toStdString())) {
- case mtx::presence::PresenceState::offline:
- return QStringLiteral("offline");
- case mtx::presence::PresenceState::unavailable:
- return QStringLiteral("unavailable");
- case mtx::presence::PresenceState::online:
- default:
- return QStringLiteral("online");
- }
-}
-
-QString
-TimelineViewManager::userStatus(QString id) const
-{
- return QString::fromStdString(cache::statusMessage(id.toStdString()));
-}
-
TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *parent)
: QObject(parent)
, imgProvider(new MxcImageProvider())
@@ -157,6 +134,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
, communities_(new CommunitiesModel(this))
, callManager_(callManager)
, verificationManager_(new VerificationManager(this))
+ , presenceEmitter(new PresenceEmitter(this))
{
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
@@ -280,6 +258,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
return new Nheko();
});
qmlRegisterSingletonInstance("im.nheko", 1, 0, "VerificationManager", verificationManager_);
+ qmlRegisterSingletonInstance("im.nheko", 1, 0, "Presence", presenceEmitter);
qmlRegisterSingletonType<SelfVerificationStatus>(
"im.nheko", 1, 0, "SelfVerificationStatus", [](QQmlEngine *, QJSEngine *) -> QObject * {
auto ptr = new SelfVerificationStatus();
@@ -407,6 +386,7 @@ TimelineViewManager::sync(const mtx::responses::Sync &sync_)
{
this->rooms_->sync(sync_);
this->communities_->sync(sync_);
+ this->presenceEmitter->sync(sync_.presence);
if (isInitialSync_) {
this->isInitialSync_ = false;
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 30b3564f..d875fd88 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -24,6 +24,7 @@
#include "emoji/Provider.h"
#include "encryption/VerificationManager.h"
#include "timeline/CommunitiesModel.h"
+#include "timeline/PresenceEmitter.h"
#include "timeline/RoomlistModel.h"
#include "voip/CallManager.h"
#include "voip/WebRTCSession.h"
@@ -64,9 +65,6 @@ public:
Q_INVOKABLE QString escapeEmoji(QString str) const;
Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); }
- Q_INVOKABLE QString userPresence(QString id) const;
- Q_INVOKABLE QString userStatus(QString id) const;
-
Q_INVOKABLE void openRoomMembers(TimelineModel *room);
Q_INVOKABLE void openRoomSettings(QString room_id);
Q_INVOKABLE void openInviteUsers(QString roomId);
@@ -146,6 +144,7 @@ private:
// don't move this above the rooms_
CallManager *callManager_ = nullptr;
VerificationManager *verificationManager_ = nullptr;
+ PresenceEmitter *presenceEmitter = nullptr;
QHash<QPair<QString, quint64>, QColor> userColors;
};
|