diff --git a/CMakeLists.txt b/CMakeLists.txt index e170495..654eae3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,6 +277,7 @@ set(SRC_FILES src/ui/Theme.cpp src/ui/ThemeManager.cpp src/ui/UserProfile.cpp + src/ui/UserProfileModel.cpp src/AvatarProvider.cpp src/BlurhashProvider.cpp @@ -482,6 +483,7 @@ qt5_wrap_cpp(MOC_HEADERS src/ui/Theme.h src/ui/ThemeManager.h src/ui/UserProfile.h + src/ui/UserProfileModel.h src/notifications/Manager.h diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index ed403aa..e4c820f 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -273,6 +273,9 @@ Page { color: colors.base } } + + property variant userProfile + Row { height: userName.height spacing: 8 @@ -287,8 +290,10 @@ Page { MouseArea { anchors.fill: parent onClicked: { - userProfile.user_data = modelData - userProfile.show() + if(userProfile) userProfile.destroy() + var component = Qt.createComponent("UserProfile.qml"); + userProfile = component.createObject(timelineRoot,{user_data : modelData}); + userProfile.show(); } cursorShape: Qt.PointingHandCursor propagateComposedEvents: true @@ -303,26 +308,17 @@ Page { MouseArea { anchors.fill: parent + Layout.alignment: Qt.AlignHCenter onClicked: { - userProfile.user_data = modelData - userProfile.show() + if(userProfile) userProfile.destroy() + var component = Qt.createComponent("UserProfile.qml") + userProfile = component.createObject(timelineRoot,{user_data : modelData}) + userProfile.show() } cursorShape: Qt.PointingHandCursor propagateComposedEvents: true } } - - Label { - color: colors.buttonText - text: timelineManager.userStatus(modelData.userId) - textFormat: Text.PlainText - elide: Text.ElideRight - width: chat.delegateMaxWidth - parent.spacing*2 - userName.implicitWidth - avatarSize - font.italic: true - } - UserProfile{ - id: userProfile - } } } } diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index ae91abc..f29fb4c 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -16,25 +16,16 @@ ApplicationWindow{ Layout.alignment: Qt.AlignHCenter palette: colors - onAfterRendering: { - userProfileAvatar.url = chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/") - userProfileName.text = user_data.userName - matrixUserID.text = user_data.userId - userProfile.userId = user_data.userId - log_devices() - } - - function log_devices() - { - console.log(userProfile.deviceList); - userProfile.deviceList.forEach((item,index)=>{ - console.log(item.device_id) - console.log(item.display_name) - }) - } - - UserProfileContent{ - id: userProfile + UserProfileList{ + id: userProfileList + userId: user_data.userId + onUserIdChanged : { + console.log(userId) + userProfileList.updateDeviceList() + } + onDeviceListUpdated : { + modelDeviceList.deviceList = userProfileList + } } background: Item{ @@ -52,6 +43,7 @@ ApplicationWindow{ Avatar{ id: userProfileAvatar + url:chat.model.avatarUrl(user_data.userId).replace("mxc://", "image://MxcImage/") height: 130 width: 130 displayName: modelData.userName @@ -60,12 +52,14 @@ ApplicationWindow{ Label{ id: userProfileName + text: user_data.userName fontSizeMode: Text.HorizontalFit Layout.alignment: Qt.AlignHCenter } Label{ id: matrixUserID + text: user_data.userId fontSizeMode: Text.HorizontalFit Layout.alignment: Qt.AlignHCenter } @@ -78,9 +72,29 @@ ApplicationWindow{ ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn - Label { - text: "ABC" - font.pixelSize: 700 + ListView{ + id: deviceList + anchors.fill: parent + clip: true + spacing: 10 + + model: UserProfileModel{ + id: modelDeviceList + } + + delegate: RowLayout{ + width: parent.width + Text{ + Layout.fillWidth: true + color: colors.text + text: deviceID + } + Text{ + Layout.fillWidth: true + color:colors.text + text: displayName + } + } } } diff --git a/src/Olm.cpp b/src/Olm.cpp index 494bc20..74fbac9 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -56,7 +56,6 @@ handle_to_device_messages(const std::vectorwarn("validation error for olm message: {} {}", e.what(), j_msg.dump(2)); - } } else if (msg_type == to_string(mtx::events::EventType::RoomKeyRequest)) { @@ -399,7 +398,6 @@ handle_key_request_message(const mtx::events::DeviceEventdebug("ignoring all key requests for room {}", req.content.room_id); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 227b410..f4d1c00 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "BlurhashProvider.h" #include "ChatPage.h" @@ -16,6 +17,8 @@ #include "emoji/EmojiModel.h" #include "emoji/Provider.h" #include "../ui/UserProfile.h" +#include "src/ui/UserProfile.h" +#include "src/ui/UserProfileModel.h" Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) @@ -87,8 +90,9 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow"); - qmlRegisterType("im.nheko",1,0,"UserProfileContent"); - qRegisterMetaType(); + qmlRegisterType("im.nheko", 1, 0, "UserProfileModel"); + qmlRegisterType("im.nheko", 1, 0, "UserProfileList"); + qRegisterMetaType(); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel"); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 3078569..588d696 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -2,29 +2,32 @@ #include "Logging.h" #include "Utils.h" #include "mtx/responses/crypto.hpp" -#include UserProfile::UserProfile(QObject *parent) : QObject(parent) {} QVector -UserProfile::getDeviceList(){ - UserProfile::fetchDeviceList(this->userId); +UserProfile::getDeviceList() +{ return this->deviceList; } QString -UserProfile::getUserId (){ +UserProfile::getUserId() +{ return this->userId; } void -UserProfile::setUserId (const QString &user_id){ - if(this->userId != userId) +UserProfile::setUserId(const QString &user_id) +{ + if (this->userId != userId) return; - else + else { this->userId = user_id; + emit UserProfile::userIdChanged(); + } } void @@ -37,11 +40,11 @@ UserProfile::fetchDeviceList(const QString &userID) http::client()->query_keys( req, - [user_id = userID.toStdString(),this](const mtx::responses::QueryKeys &res, - mtx::http::RequestErr err) { + [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err) { if (err) { - nhlog::net()->warn("failed to query device keys: {} {}", - err->matrix_error.error, + nhlog::net()->warn("failed to query device keys: {},{}", + err->matrix_error.errcode, static_cast(err->status_code)); return; } @@ -53,17 +56,16 @@ UserProfile::fetchDeviceList(const QString &userID) } auto devices = res.device_keys.at(user_id); - QVector deviceInfo; + for (const auto &d : devices) { auto device = d.second; // TODO: Verify signatures and ignore those that don't pass. - // std::cout<device_id = QString::fromStdString(d.first); - newdevice->display_name = QString::fromStdString(device.unsigned_info.device_display_name) + DeviceInfo newdevice( + QString::fromStdString(d.first), + QString::fromStdString(device.unsigned_info.device_display_name)); + QString::fromStdString(device.unsigned_info.device_display_name); deviceInfo.append(std::move(newdevice)); } @@ -74,7 +76,13 @@ UserProfile::fetchDeviceList(const QString &userID) return a.device_id > b.device_id; }); - this->deviceList = deviceInfo; - emit UserProfile::deviceListUpdated(); + this->deviceList = std::move(deviceInfo); + emit UserProfile::deviceListUpdated(); }); } + +void +UserProfile::updateDeviceList() +{ + fetchDeviceList(this->userId); +} diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index bbf57c7..c37e23a 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -2,33 +2,29 @@ #include #include +#include #include "MatrixClient.h" class DeviceInfo { public: - explicit DeviceInfo(QString device_id,QString display_name){ - this->device_id = device_id; - this->display_name = display_name; - } - ~DeviceInfo() = default; - DeviceInfo(const DeviceInfo &device){ - this->device_id = device.device_id; - this->display_name = device.display_name; - } + DeviceInfo(const QString deviceID, const QString displayName) + : device_id(deviceID) + , display_name(displayName) + {} + + DeviceInfo() {} QString device_id; QString display_name; }; -Q_DECLARE_METATYPE(DeviceInfo); class UserProfile : public QObject { Q_OBJECT + Q_PROPERTY(QString userId READ getUserId WRITE setUserId NOTIFY userIdChanged) Q_PROPERTY(QVector deviceList READ getDeviceList NOTIFY deviceListUpdated) - Q_PROPERTY(QString userId READ getUserId WRITE setUserId) - public: // constructor explicit UserProfile(QObject *parent = 0); @@ -39,8 +35,10 @@ public: void setUserId(const QString &userId); Q_INVOKABLE void fetchDeviceList(const QString &userID); + Q_INVOKABLE void updateDeviceList(); signals: + void userIdChanged(); void deviceListUpdated(); private: diff --git a/src/ui/UserProfileModel.cpp b/src/ui/UserProfileModel.cpp new file mode 100644 index 0000000..ec0456c --- /dev/null +++ b/src/ui/UserProfileModel.cpp @@ -0,0 +1,66 @@ +#include "UserProfileModel.h" +#include "UserProfile.h" +#include + +UserProfileModel::UserProfileModel(QObject *parent) + : QAbstractListModel(parent) + , deviceList(nullptr) +{} + +int +UserProfileModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() || !this->deviceList) + return 0; + return this->deviceList->getDeviceList().size(); +} + +QVariant +UserProfileModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || !this->deviceList) + return QVariant(); + + const DeviceInfo device = this->deviceList->getDeviceList().at(index.row()); + switch (role) { + case DEVICEID: + return QVariant(device.device_id); + case DISPLAYNAME: + return QVariant(device.display_name); + } + return QVariant(); +} + +QHash +UserProfileModel::roleNames() const +{ + QHash names; + names[DEVICEID] = "deviceID"; + names[DISPLAYNAME] = "displayName"; + return names; +} + +UserProfile * +UserProfileModel::getList() const +{ + return (this->deviceList); +} + +void +UserProfileModel::setList(UserProfile *devices) +{ + beginResetModel(); + + if (devices) + devices->disconnect(this); + + if (this->deviceList) { + const int index = this->deviceList->getDeviceList().size(); + beginInsertRows(QModelIndex(), index, index); + endInsertRows(); + } + + this->deviceList = devices; + + endResetModel(); +} \ No newline at end of file diff --git a/src/ui/UserProfileModel.h b/src/ui/UserProfileModel.h new file mode 100644 index 0000000..c21a806 --- /dev/null +++ b/src/ui/UserProfileModel.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +class UserProfile; // forward declaration of the class UserProfile + +class UserProfileModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(UserProfile *deviceList READ getList WRITE setList) + +public: + explicit UserProfileModel(QObject *parent = nullptr); + + enum + { + DEVICEID, + DISPLAYNAME + }; + UserProfile *getList() const; + void setList(UserProfile *devices); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + virtual QHash roleNames() const override; + +private: + UserProfile *deviceList; +}; \ No newline at end of file