summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--resources/qml/TimelineView.qml25
-rw-r--r--src/Cache.cpp15
-rw-r--r--src/CacheStructs.h1
-rw-r--r--src/Cache_p.h13
-rw-r--r--src/timeline/RoomlistModel.cpp46
-rw-r--r--src/timeline/RoomlistModel.h6
6 files changed, 102 insertions, 4 deletions
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 24489d0b..18085f28 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -283,6 +283,29 @@ Item {
 
             onClicked: TimelineManager.openLeaveRoomDialog(room.roomId)
         }
+        RowLayout {
+            Layout.alignment: Qt.AlignHCenter
+            spacing: Nheko.paddingMedium
+            visible: roomPreview && roomPreview.isInvite && reasonField.showReason
+
+            MatrixText {
+                text: qsTr("Invited by %1 (%2)").arg(TimelineManager.escapeEmoji(inviterAvatar.displayName)).arg(TimelineManager.escapeEmoji(TimelineManager.htmlEscape(inviterAvatar.userid)))
+            }
+            Avatar {
+                id: inviterAvatar
+
+                Layout.alignment: Qt.AlignHCenter
+                displayName: roomPreview?.inviterDisplayName ?? ""
+                enabled: true
+                height: 48
+                roomid: preview.roomId
+                url: (roomPreview?.inviterAvatarUrl ?? "").replace("mxc://", "image://MxcImage/")
+                userid: roomPreview?.inviterUserId ?? ""
+                width: 48
+
+                onClicked: TimelineManager.openGlobalUserProfile(roomPreview.inviterUserId)
+            }
+        }
         ScrollView {
             id: reasonField
 
@@ -312,7 +335,7 @@ Item {
             Layout.leftMargin: Nheko.paddingLarge
             Layout.rightMargin: Nheko.paddingLarge
             text: reasonField.showReason ? qsTr("Hide invite reason") : qsTr("Show invite reason")
-            visible: preview.reason !== ""
+            visible: roomPreview && roomPreview.isInvite
 
             onClicked: {
                 reasonField.showReason = !reasonField.showReason;
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 7671af02..f4aad6b3 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -2128,8 +2128,16 @@ Cache::saveInvite(lmdb::txn &txn,
             auto display_name =
               msg->content.display_name.empty() ? msg->state_key : msg->content.display_name;
 
-            MemberInfo tmp{
-              display_name, msg->content.avatar_url, msg->content.reason, msg->content.is_direct};
+            std::string inviter = "";
+            if (msg->content.membership == mtx::events::state::Membership::Invite) {
+                inviter = msg->sender;
+            }
+
+            MemberInfo tmp{display_name,
+                           msg->content.avatar_url,
+                           inviter,
+                           msg->content.reason,
+                           msg->content.is_direct};
 
             membersdb.put(txn, msg->state_key, nlohmann::json(tmp).dump());
         } else {
@@ -5173,6 +5181,8 @@ to_json(nlohmann::json &j, const MemberInfo &info)
 {
     j["name"]       = info.name;
     j["avatar_url"] = info.avatar_url;
+    if (!info.inviter.empty())
+        j["inviter"] = info.inviter;
     if (info.is_direct)
         j["is_direct"] = info.is_direct;
     if (!info.reason.empty())
@@ -5186,6 +5196,7 @@ from_json(const nlohmann::json &j, MemberInfo &info)
     info.avatar_url = j.value("avatar_url", "");
     info.is_direct  = j.value("is_direct", false);
     info.reason     = j.value("reason", "");
+    info.inviter    = j.value("inviter", "");
 }
 
 void
diff --git a/src/CacheStructs.h b/src/CacheStructs.h
index 6dad4b19..13c24c99 100644
--- a/src/CacheStructs.h
+++ b/src/CacheStructs.h
@@ -117,6 +117,7 @@ struct MemberInfo
 {
     std::string name;
     std::string avatar_url;
+    std::string inviter = "";
     std::string reason = "";
     bool is_direct     = false;
 };
diff --git a/src/Cache_p.h b/src/Cache_p.h
index f8716e81..121e7e66 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -394,8 +394,19 @@ private:
                 auto display_name =
                   e->content.display_name.empty() ? e->state_key : e->content.display_name;
 
+                std::string inviter = "";
+                if (e->content.membership == mtx::events::state::Membership::Invite) {
+                    inviter = e->sender;
+                }
+
                 // Lightweight representation of a member.
-                MemberInfo tmp{display_name, e->content.avatar_url, e->content.reason};
+                MemberInfo tmp{
+                  display_name,
+                  e->content.avatar_url,
+                  inviter,
+                  e->content.reason,
+                  e->content.is_direct,
+                };
 
                 membersdb.put(txn, e->state_key, nlohmann::json(tmp).dump());
                 break;
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 35507cbd..ec41cc12 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -1235,3 +1235,49 @@ FilteredRoomlistModel::previousRoom()
         }
     }
 }
+
+QString
+RoomPreview::inviterAvatarUrl() const
+{
+    if (isInvite_) {
+        auto self = cache::client()->getInviteMember(roomid_.toStdString(),
+                                                     http::client()->user_id().to_string());
+        if (self && !self->inviter.empty()) {
+            auto other = cache::client()->getInviteMember(roomid_.toStdString(), self->inviter);
+            if (other && other->avatar_url.starts_with("mxc://")) {
+                return QString::fromStdString(other->avatar_url);
+            }
+        }
+    }
+
+    return QString();
+}
+QString
+RoomPreview::inviterDisplayName() const
+{
+    if (isInvite_) {
+        auto self = cache::client()->getInviteMember(roomid_.toStdString(),
+                                                     http::client()->user_id().to_string());
+        if (self && !self->inviter.empty()) {
+            auto other = cache::client()->getInviteMember(roomid_.toStdString(), self->inviter);
+            if (other) {
+                return QString::fromStdString(other->name).toHtmlEscaped();
+            }
+        }
+    }
+
+    return QString();
+}
+QString
+RoomPreview::inviterUserId() const
+{
+    if (isInvite_) {
+        auto self = cache::client()->getInviteMember(roomid_.toStdString(),
+                                                     http::client()->user_id().to_string());
+        if (self && !self->inviter.empty()) {
+            return QString::fromStdString(self->inviter);
+        }
+    }
+
+    return QString();
+}
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 9aaafc06..c06ab67d 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -31,6 +31,9 @@ class RoomPreview
     Q_PROPERTY(QString roomTopic READ roomTopic CONSTANT)
     Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl CONSTANT)
     Q_PROPERTY(QString reason READ reason CONSTANT)
+    Q_PROPERTY(QString inviterAvatarUrl READ inviterAvatarUrl CONSTANT)
+    Q_PROPERTY(QString inviterDisplayName READ inviterDisplayName CONSTANT)
+    Q_PROPERTY(QString inviterUserId READ inviterUserId CONSTANT)
     Q_PROPERTY(bool isInvite READ isInvite CONSTANT)
     Q_PROPERTY(bool isFetched READ isFetched CONSTANT)
 
@@ -42,6 +45,9 @@ public:
     QString roomTopic() const { return roomTopic_; }
     QString roomAvatarUrl() const { return roomAvatarUrl_; }
     QString reason() const { return reason_; }
+    QString inviterAvatarUrl() const;
+    QString inviterDisplayName() const;
+    QString inviterUserId() const;
     bool isInvite() const { return isInvite_; }
     bool isFetched() const { return isFetched_; }