summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--resources/qml/TimelineView.qml22
-rw-r--r--resources/qml/UserProfile.qml417
-rw-r--r--src/MainWindow.cpp9
-rw-r--r--src/MainWindow.h2
-rw-r--r--src/dialogs/UserProfile.cpp305
-rw-r--r--src/dialogs/UserProfile.h69
-rw-r--r--src/timeline/TimelineModel.cpp4
-rw-r--r--src/timeline/TimelineModel.h10
-rw-r--r--src/timeline/TimelineViewManager.cpp20
-rw-r--r--src/ui/UserProfile.cpp108
-rw-r--r--src/ui/UserProfile.h120
-rw-r--r--src/ui/UserProfileModel.cpp63
-rw-r--r--src/ui/UserProfileModel.h30
14 files changed, 383 insertions, 800 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c39ff3af..5ad8a625 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -240,7 +240,6 @@ set(SRC_FILES
 	src/dialogs/ReCaptcha.cpp
 	src/dialogs/ReadReceipts.cpp
 	src/dialogs/RoomSettings.cpp
-	src/dialogs/UserProfile.cpp
 
 	# Emoji
 	src/emoji/Category.cpp
@@ -280,7 +279,6 @@ 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
@@ -449,7 +447,6 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/dialogs/ReCaptcha.h
 	src/dialogs/ReadReceipts.h
 	src/dialogs/RoomSettings.h
-	src/dialogs/UserProfile.h
 
 	# Emoji
 	src/emoji/Category.h
@@ -486,7 +483,6 @@ 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 3618140a..ec634878 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -106,17 +106,23 @@ Page {
 		}
 		Connections {
 			target: TimelineManager
-			onNewDeviceVerificationRequest: {
+			function onNewDeviceVerificationRequest(flow) {
 				flow.userId = userId;
 				flow.sender = false;
 				flow.deviceId = deviceId;
 				flow.tranId = transactionId;
 				deviceVerificationList.add(flow.tranId);
-				var dialog = deviceVerificationDialog.createObject(timelineRoot, 
-                    {flow: flow});
+				var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow});
 				dialog.show();
 			}
 		}
+		Connections {
+			target: TimelineManager.timeline
+			function onOpenProfile(profile) {
+				var userProfile = userProfileComponent.createObject(timelineRoot,{profile: profile});
+				userProfile.show();
+			}
+		}
 
 		Label {
 			visible: !TimelineManager.timeline && !TimelineManager.isInitialSync
@@ -293,10 +299,7 @@ Page {
 
 							MouseArea {
 								anchors.fill: parent
-                                onClicked: {
-									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
-									userProfile.show();
-                                }
+								onClicked: chat.model.openUserProfile(modelData.userId)
 								cursorShape: Qt.PointingHandCursor
 								propagateComposedEvents: true
 							}
@@ -311,10 +314,7 @@ Page {
 							MouseArea {
 								anchors.fill: parent
 								Layout.alignment: Qt.AlignHCenter
-                                onClicked: {
-									userProfile = userProfileComponent.createObject(timelineRoot,{user_data: modelData,avatarUrl:chat.model.avatarUrl(modelData.userId)});
-									userProfile.show();
-                                }
+								onClicked: chat.model.openUserProfile(modelData.userId)
 								cursorShape: Qt.PointingHandCursor
 								propagateComposedEvents: true
 							}
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index db44ec15..df54367b 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -8,220 +8,211 @@ import im.nheko 1.0
 import "./device-verification"
 
 ApplicationWindow{
-    property var user_data
-    property var avatarUrl
-    property var colors: currentActivePalette
-
-    id:userProfileDialog
-    height: 650
-    width: 420
-    modality:Qt.WindowModal
-    Layout.alignment: Qt.AlignHCenter
-    palette: colors
-
-    Component {
+	property var profile
+
+	id: userProfileDialog
+	height: 650
+	width: 420
+	modality: Qt.WindowModal
+	Layout.alignment: Qt.AlignHCenter
+	palette: colors
+
+	Component {
 		id: deviceVerificationDialog
 		DeviceVerification {}
 	}
-    Component{
-        id: deviceVerificationFlow
-        DeviceVerificationFlow {}
-    }
-
-    background: Item{
-        id: userProfileItem
-        width: userProfileDialog.width
-        height: userProfileDialog.height
-
-        // Layout.fillHeight : true
-
-        ColumnLayout{
-            anchors.fill: userProfileItem
-            width: userProfileDialog.width
-            spacing: 10
-
-            Avatar{
-                id: userProfileAvatar
-                url: avatarUrl.replace("mxc://", "image://MxcImage/")
-                height: 130
-                width: 130
-                displayName: user_data.userName
-		        userid: user_data.userId
-                Layout.alignment: Qt.AlignHCenter
-                Layout.margins : {
-                    top: 10
-                }
-            }
-
-            Label{
-                id: userProfileName
-                text: user_data.userName
-                fontSizeMode: Text.HorizontalFit
-                font.pixelSize: 20
-                color:TimelineManager.userColor(user_data.userId, colors.window)
-                font.bold: true
-                Layout.alignment: Qt.AlignHCenter
-            }
-
-            Label{
-                id: matrixUserID
-                text: user_data.userId
-                fontSizeMode: Text.HorizontalFit
-                font.pixelSize: 15
-                color:colors.text
-                Layout.alignment: Qt.AlignHCenter
-            }
-
-            RowLayout{
-                Layout.alignment: Qt.AlignHCenter
-                ImageButton{
-                    image:":/icons/icons/ui/do-not-disturb-rounded-sign.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Ban the user")
-                    onClicked : {
-                        modelDeviceList.deviceList.banUser()
-                    }
-                }
-                // ImageButton{
-                //     image:":/icons/icons/ui/volume-off-indicator.png"
-                //     Layout.margins: {
-                //         left: 5
-                //         right: 5
-                //     }
-                //     ToolTip.visible: hovered
-			    //     ToolTip.text: qsTr("Ignore messages from this user")
-                //     onClicked : {
-                //         modelDeviceList.deviceList.ignoreUser()
-                //     }
-                // }
-                ImageButton{
-                    image:":/icons/icons/ui/black-bubble-speech.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Start a private chat")
-                    onClicked : {
-                        modelDeviceList.deviceList.startChat()
-                    }
-                }
-                ImageButton{
-                    image:":/icons/icons/ui/round-remove-button.png"
-                    Layout.margins: {
-                        left: 5
-                        right: 5
-                    }
-                    ToolTip.visible: hovered
-			        ToolTip.text: qsTr("Kick the user")
-                    onClicked : {
-                        modelDeviceList.deviceList.kickUser()
-                    }
-                }
-            }
-
-            ScrollView {
-                implicitHeight: userProfileDialog.height/2 + 20
-                implicitWidth: userProfileDialog.width-20
-                clip: true
-                Layout.alignment: Qt.AlignHCenter
-
-                ListView{
-                    id: devicelist
-                    anchors.fill: parent
-                    clip: true
-                    spacing: 4
-
-                    model: UserProfileModel{
-                        id: modelDeviceList
-                        deviceList.userId : user_data.userId
-                    }
-
-                    delegate: RowLayout{
-                        width: parent.width
-                        Layout.margins : {
-                            top : 50
-                        }
-                        ColumnLayout{
-                            RowLayout{
-                                Text{
-                                    Layout.fillWidth: true
-                                    color: colors.text
-                                    font.bold: true
-                                    Layout.alignment: Qt.AlignLeft
-                                    text: deviceID
-                                }
-                                Text{
-                                    Layout.fillWidth: true
-                                    color:colors.text
-                                    Layout.alignment: Qt.AlignLeft
-                                    text: (verified_status ==  UserProfileList.VERIFIED?"V":(verified_status ==  UserProfileList.UNVERIFIED?"NV":"B"))
-                                }
-                            }
-                            Text{
-                                Layout.fillWidth: true
-                                color:colors.text
-                                Layout.alignment: Qt.AlignRight
-                                text: displayName
-                            }
-                        }
-                        Button{
-                            id: verifyButton
-                            text:"Verify"
-                            onClicked: {
-                                var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
-                                {userId : user_data.userId,sender: true,deviceId : model.deviceID});
-                                deviceVerificationList.add(newFlow.tranId);
-								var dialog = deviceVerificationDialog.createObject(userProfileDialog, 
-                                    {flow: newFlow});
-				                dialog.show();
-                            }
-                            Layout.margins:{
-                                right: 10
-                            }
-                            palette {
-                                button: "white"
-                            }
-                            contentItem: Text {
-                                text: verifyButton.text
-                                color: "black"
-                                horizontalAlignment: Text.AlignHCenter
-                                verticalAlignment: Text.AlignVCenter
-                            }
-                        }
-                    }
-                }
-            }
-
-            Button{
-                id: okbutton
-                text:"OK"
-                onClicked: userProfileDialog.close()
-                
-                Layout.alignment: Qt.AlignRight | Qt.AlignBottom
-
-                Layout.margins : {
-                    right : 10
-                    bottom: 5
-                }
-
-                palette {
-                    button: "white"
-                }
-
-                contentItem: Text {
-                    text: okbutton.text
-                    color: "black"
-                    horizontalAlignment: Text.AlignHCenter
-                    verticalAlignment: Text.AlignVCenter
-                }
-            }
-        }
-
-        Item { Layout.fillHeight: true }
-    }
+	Component{
+		id: deviceVerificationFlow
+		DeviceVerificationFlow {}
+	}
+
+	background: Item{
+		id: userProfileItem
+		width: userProfileDialog.width
+		height: userProfileDialog.height
+
+		// Layout.fillHeight : true
+
+		ColumnLayout{
+			anchors.fill: userProfileItem
+			width: userProfileDialog.width
+			spacing: 10
+
+			Avatar {
+				url: profile.avatarUrl.replace("mxc://", "image://MxcImage/")
+				height: 130
+				width: 130
+				displayName: profile.displayName
+				userid: profile.userid
+				Layout.alignment: Qt.AlignHCenter
+				Layout.margins : {
+					top: 10
+				}
+			}
+
+			Label {
+				text: profile.displayName
+				fontSizeMode: Text.HorizontalFit
+				font.pixelSize: 20
+				color: TimelineManager.userColor(profile.userid, colors.window)
+				font.bold: true
+				Layout.alignment: Qt.AlignHCenter
+			}
+
+			Label {
+				text: profile.userid
+				fontSizeMode: Text.HorizontalFit
+				font.pixelSize: 15
+				color: colors.text
+				Layout.alignment: Qt.AlignHCenter
+			}
+
+			RowLayout {
+				Layout.alignment: Qt.AlignHCenter
+				ImageButton {
+					image:":/icons/icons/ui/do-not-disturb-rounded-sign.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Ban the user")
+					onClicked : {
+						profile.banUser()
+					}
+				}
+				// ImageButton{
+				//     image:":/icons/icons/ui/volume-off-indicator.png"
+				//     Layout.margins: {
+				//         left: 5
+				//         right: 5
+				//     }
+				//     ToolTip.visible: hovered
+				//     ToolTip.text: qsTr("Ignore messages from this user")
+				//     onClicked : {
+				//         profile.ignoreUser()
+				//     }
+				// }
+				ImageButton{
+					image:":/icons/icons/ui/black-bubble-speech.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Start a private chat")
+					onClicked : {
+						profile.startChat()
+					}
+				}
+				ImageButton{
+					image:":/icons/icons/ui/round-remove-button.png"
+					Layout.margins: {
+						left: 5
+						right: 5
+					}
+					ToolTip.visible: hovered
+					ToolTip.text: qsTr("Kick the user")
+					onClicked : {
+						profile.kickUser()
+					}
+				}
+			}
+
+			ScrollView {
+				implicitHeight: userProfileDialog.height/2 + 20
+				implicitWidth: userProfileDialog.width-20
+				clip: true
+				Layout.alignment: Qt.AlignHCenter
+
+				ListView{
+					id: devicelist
+					anchors.fill: parent
+					clip: true
+					spacing: 4
+
+					model: profile.deviceList
+
+					delegate: RowLayout{
+						width: parent.width
+						Layout.margins : {
+							top : 50
+						}
+						ColumnLayout{
+							RowLayout{
+								Text{
+									Layout.fillWidth: true
+									color: colors.text
+									font.bold: true
+									Layout.alignment: Qt.AlignLeft
+									text: model.deviceId
+								}
+								Text{
+									Layout.fillWidth: true
+									color:colors.text
+									Layout.alignment: Qt.AlignLeft
+									text: (model.verificationStatus ==  VerificationStatus.VERIFIED?"V":(model.verificationStatus ==  VerificationStatus.UNVERIFIED?"NV":"B"))
+								}
+							}
+							Text{
+								Layout.fillWidth: true
+								color:colors.text
+								Layout.alignment: Qt.AlignRight
+								text: model.deviceName
+							}
+						}
+						Button{
+							id: verifyButton
+							text:"Verify"
+							onClicked: {
+								var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
+								{userId : profile.userid, sender: true, deviceId : model.deviceID});
+								deviceVerificationList.add(newFlow.tranId);
+								var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow});
+								dialog.show();
+							}
+							Layout.margins:{
+								right: 10
+							}
+							palette {
+								button: "white"
+							}
+							contentItem: Text {
+								text: verifyButton.text
+								color: "black"
+								horizontalAlignment: Text.AlignHCenter
+								verticalAlignment: Text.AlignVCenter
+							}
+						}
+					}
+				}
+			}
+
+			Button{
+				id: okbutton
+				text:"OK"
+				onClicked: userProfileDialog.close()
+
+				Layout.alignment: Qt.AlignRight | Qt.AlignBottom
+
+				Layout.margins : {
+					right : 10
+					bottom: 5
+				}
+
+				palette {
+					button: "white"
+				}
+
+				contentItem: Text {
+					text: okbutton.text
+					color: "black"
+					horizontalAlignment: Text.AlignHCenter
+					verticalAlignment: Text.AlignVCenter
+				}
+			}
+		}
+
+		Item { Layout.fillHeight: true }
+	}
 }
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index cc1d868b..63b524c8 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -318,15 +318,6 @@ MainWindow::hasActiveUser()
 }
 
 void
-MainWindow::openUserProfile(const QString &user_id, const QString &room_id)
-{
-        auto dialog = new dialogs::UserProfile(this);
-        dialog->init(user_id, room_id);
-
-        showDialog(dialog);
-}
-
-void
 MainWindow::openRoomSettings(const QString &room_id)
 {
         const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : "";
diff --git a/src/MainWindow.h b/src/MainWindow.h
index e3e04698..2fc2d00f 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -25,7 +25,6 @@
 #include <QSystemTrayIcon>
 
 #include "UserSettingsPage.h"
-#include "dialogs/UserProfile.h"
 #include "ui/OverlayModal.h"
 
 #include "jdenticoninterface.h"
@@ -76,7 +75,6 @@ public:
         void openLogoutDialog();
         void openRoomSettings(const QString &room_id = "");
         void openMemberListDialog(const QString &room_id = "");
-        void openUserProfile(const QString &user_id, const QString &room_id);
         void openReadReceiptsDialog(const QString &event_id);
 
         void hideOverlay();
diff --git a/src/dialogs/UserProfile.cpp b/src/dialogs/UserProfile.cpp
deleted file mode 100644
index 3415b127..00000000
--- a/src/dialogs/UserProfile.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-#include <QHBoxLayout>
-#include <QLabel>
-#include <QListWidget>
-#include <QShortcut>
-#include <QVBoxLayout>
-
-#include "Cache.h"
-#include "ChatPage.h"
-#include "Logging.h"
-#include "MatrixClient.h"
-#include "Utils.h"
-#include "dialogs/UserProfile.h"
-#include "ui/Avatar.h"
-#include "ui/FlatButton.h"
-
-using namespace dialogs;
-
-Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
-
-constexpr int BUTTON_SIZE       = 36;
-constexpr int BUTTON_RADIUS     = BUTTON_SIZE / 2;
-constexpr int WIDGET_MARGIN     = 20;
-constexpr int TOP_WIDGET_MARGIN = 2 * WIDGET_MARGIN;
-constexpr int WIDGET_SPACING    = 15;
-constexpr int TEXT_SPACING      = 4;
-constexpr int DEVICE_SPACING    = 5;
-
-DeviceItem::DeviceItem(DeviceInfo device, QWidget *parent)
-  : QWidget(parent)
-  , info_(std::move(device))
-{
-        QFont font;
-        font.setBold(true);
-
-        auto deviceIdLabel = new QLabel(info_.device_id, this);
-        deviceIdLabel->setFont(font);
-
-        auto layout = new QVBoxLayout{this};
-        layout->addWidget(deviceIdLabel);
-
-        if (!info_.display_name.isEmpty())
-                layout->addWidget(new QLabel(info_.display_name, this));
-
-        layout->setMargin(0);
-        layout->setSpacing(4);
-}
-
-UserProfile::UserProfile(QWidget *parent)
-  : QWidget(parent)
-{
-        setAutoFillBackground(true);
-        setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
-        setAttribute(Qt::WA_DeleteOnClose, true);
-
-        QIcon banIcon, kickIcon, ignoreIcon, startChatIcon;
-
-        banIcon.addFile(":/icons/icons/ui/do-not-disturb-rounded-sign.png");
-        banBtn_ = new FlatButton(this);
-        banBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        banBtn_->setCornerRadius(BUTTON_RADIUS);
-        banBtn_->setIcon(banIcon);
-        banBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        banBtn_->setToolTip(tr("Ban the user from the room"));
-
-        ignoreIcon.addFile(":/icons/icons/ui/volume-off-indicator.png");
-        ignoreBtn_ = new FlatButton(this);
-        ignoreBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        ignoreBtn_->setCornerRadius(BUTTON_RADIUS);
-        ignoreBtn_->setIcon(ignoreIcon);
-        ignoreBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        ignoreBtn_->setToolTip(tr("Ignore messages from this user"));
-        ignoreBtn_->setDisabled(true); // Not used yet.
-
-        kickIcon.addFile(":/icons/icons/ui/round-remove-button.png");
-        kickBtn_ = new FlatButton(this);
-        kickBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        kickBtn_->setCornerRadius(BUTTON_RADIUS);
-        kickBtn_->setIcon(kickIcon);
-        kickBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        kickBtn_->setToolTip(tr("Kick the user from the room"));
-
-        startChatIcon.addFile(":/icons/icons/ui/black-bubble-speech.png");
-        startChat_ = new FlatButton(this);
-        startChat_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
-        startChat_->setCornerRadius(BUTTON_RADIUS);
-        startChat_->setIcon(startChatIcon);
-        startChat_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS));
-        startChat_->setToolTip(tr("Start a conversation"));
-
-        connect(startChat_, &QPushButton::clicked, this, [this]() {
-                auto user_id = userIdLabel_->text();
-
-                mtx::requests::CreateRoom req;
-                req.preset     = mtx::requests::Preset::PrivateChat;
-                req.visibility = mtx::requests::Visibility::Private;
-
-                if (utils::localUser() != user_id)
-                        req.invite = {user_id.toStdString()};
-
-                emit ChatPage::instance()->createRoom(req);
-        });
-
-        connect(banBtn_, &QPushButton::clicked, this, [this] {
-                ChatPage::instance()->banUser(userIdLabel_->text(), "");
-        });
-        connect(kickBtn_, &QPushButton::clicked, this, [this] {
-                ChatPage::instance()->kickUser(userIdLabel_->text(), "");
-        });
-
-        // Button line
-        auto btnLayout = new QHBoxLayout;
-        btnLayout->addStretch(1);
-        btnLayout->addWidget(startChat_);
-        btnLayout->addWidget(ignoreBtn_);
-
-        btnLayout->addWidget(kickBtn_);
-        btnLayout->addWidget(banBtn_);
-        btnLayout->addStretch(1);
-        btnLayout->setSpacing(8);
-        btnLayout->setMargin(0);
-
-        avatar_ = new Avatar(this, 128);
-        avatar_->setLetter("X");
-
-        QFont font;
-        font.setPointSizeF(font.pointSizeF() * 2);
-
-        userIdLabel_      = new QLabel(this);
-        displayNameLabel_ = new QLabel(this);
-        displayNameLabel_->setFont(font);
-
-        auto textLayout = new QVBoxLayout;
-        textLayout->addWidget(displayNameLabel_);
-        textLayout->addWidget(userIdLabel_);
-        textLayout->setAlignment(displayNameLabel_, Qt::AlignCenter | Qt::AlignTop);
-        textLayout->setAlignment(userIdLabel_, Qt::AlignCenter | Qt::AlignTop);
-        textLayout->setSpacing(TEXT_SPACING);
-        textLayout->setMargin(0);
-
-        devices_ = new QListWidget{this};
-        devices_->setFrameStyle(QFrame::NoFrame);
-        devices_->setSelectionMode(QAbstractItemView::NoSelection);
-        devices_->setAttribute(Qt::WA_MacShowFocusRect, 0);
-        devices_->setSpacing(DEVICE_SPACING);
-
-        QFont descriptionLabelFont;
-        descriptionLabelFont.setWeight(65);
-
-        devicesLabel_ = new QLabel(tr("Devices").toUpper(), this);
-        devicesLabel_->setFont(descriptionLabelFont);
-        devicesLabel_->hide();
-        devicesLabel_->setFixedSize(devicesLabel_->sizeHint());
-
-        auto okBtn = new QPushButton("OK", this);
-
-        auto closeLayout = new QHBoxLayout();
-        closeLayout->setSpacing(15);
-        closeLayout->addStretch(1);
-        closeLayout->addWidget(okBtn);
-
-        auto vlayout = new QVBoxLayout{this};
-        vlayout->addWidget(avatar_, 0, Qt::AlignCenter | Qt::AlignTop);
-        vlayout->addLayout(textLayout);
-        vlayout->addLayout(btnLayout);
-        vlayout->addWidget(devicesLabel_, 0, Qt::AlignLeft);
-        vlayout->addWidget(devices_, 1);
-        vlayout->addLayout(closeLayout);
-
-        QFont largeFont;
-        largeFont.setPointSizeF(largeFont.pointSizeF() * 1.5);
-
-        setMinimumWidth(
-          std::max(devices_->sizeHint().width() + 4 * WIDGET_MARGIN, conf::window::minModalWidth));
-        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
-
-        vlayout->setSpacing(WIDGET_SPACING);
-        vlayout->setContentsMargins(WIDGET_MARGIN, TOP_WIDGET_MARGIN, WIDGET_MARGIN, WIDGET_MARGIN);
-
-        qRegisterMetaType<std::vector<DeviceInfo>>();
-
-        auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
-        connect(closeShortcut, &QShortcut::activated, this, &UserProfile::close);
-        connect(okBtn, &QPushButton::clicked, this, &UserProfile::close);
-}
-
-void
-UserProfile::resetToDefaults()
-{
-        avatar_->setLetter("X");
-        devices_->clear();
-
-        ignoreBtn_->show();
-        devices_->hide();
-        devicesLabel_->hide();
-}
-
-void
-UserProfile::init(const QString &userId, const QString &roomId)
-{
-        resetToDefaults();
-
-        auto displayName = cache::displayName(roomId, userId);
-
-        userIdLabel_->setText(userId);
-        displayNameLabel_->setText(displayName);
-        avatar_->setLetter(utils::firstChar(displayName));
-
-        avatar_->setImage(roomId, userId);
-
-        auto localUser = utils::localUser();
-
-        try {
-                bool hasMemberRights =
-                  cache::hasEnoughPowerLevel({mtx::events::EventType::RoomMember},
-                                             roomId.toStdString(),
-                                             localUser.toStdString());
-                if (!hasMemberRights) {
-                        kickBtn_->hide();
-                        banBtn_->hide();
-                } else {
-                        kickBtn_->show();
-                        banBtn_->show();
-                }
-        } catch (const lmdb::error &e) {
-                nhlog::db()->warn("lmdb error: {}", e.what());
-        }
-
-        if (localUser == userId) {
-                // TODO: click on display name & avatar to change.
-                kickBtn_->hide();
-                banBtn_->hide();
-                ignoreBtn_->hide();
-        }
-
-        mtx::requests::QueryKeys req;
-        req.device_keys[userId.toStdString()] = {};
-
-        // A proxy object is used to emit the signal instead of the original object
-        // which might be destroyed by the time the http call finishes.
-        auto proxy = std::make_shared<Proxy>();
-        QObject::connect(proxy.get(), &Proxy::done, this, &UserProfile::updateDeviceList);
-
-        http::client()->query_keys(
-          req,
-          [user_id = userId.toStdString(), proxy = std::move(proxy)](
-            const mtx::responses::QueryKeys &res, mtx::http::RequestErr err) {
-                  if (err) {
-                          nhlog::net()->warn("failed to query device keys: {} {}",
-                                             err->matrix_error.error,
-                                             static_cast<int>(err->status_code));
-                          // TODO: Notify the UI.
-                          return;
-                  }
-
-                  if (res.device_keys.empty() ||
-                      (res.device_keys.find(user_id) == res.device_keys.end())) {
-                          nhlog::net()->warn("no devices retrieved {}", user_id);
-                          return;
-                  }
-
-                  auto devices = res.device_keys.at(user_id);
-
-                  std::vector<DeviceInfo> deviceInfo;
-                  for (const auto &d : devices) {
-                          auto device = d.second;
-
-                          // TODO: Verify signatures and ignore those that don't pass.
-                          deviceInfo.emplace_back(DeviceInfo{
-                            QString::fromStdString(d.first),
-                            QString::fromStdString(device.unsigned_info.device_display_name)});
-                  }
-
-                  std::sort(deviceInfo.begin(),
-                            deviceInfo.end(),
-                            [](const DeviceInfo &a, const DeviceInfo &b) {
-                                    return a.device_id > b.device_id;
-                            });
-
-                  if (!deviceInfo.empty())
-                          emit proxy->done(QString::fromStdString(user_id), deviceInfo);
-          });
-}
-
-void
-UserProfile::updateDeviceList(const QString &user_id, const std::vector<DeviceInfo> &devices)
-{
-        if (user_id != userIdLabel_->text())
-                return;
-
-        for (const auto &dev : devices) {
-                auto deviceItem = new DeviceItem(dev, this);
-                auto item       = new QListWidgetItem;
-
-                item->setSizeHint(deviceItem->minimumSizeHint());
-                item->setFlags(Qt::NoItemFlags);
-                item->setTextAlignment(Qt::AlignCenter);
-
-                devices_->insertItem(devices_->count() - 1, item);
-                devices_->setItemWidget(item, deviceItem);
-        }
-
-        devicesLabel_->show();
-        devices_->show();
-        adjustSize();
-}
diff --git a/src/dialogs/UserProfile.h b/src/dialogs/UserProfile.h
deleted file mode 100644
index 81276d2a..00000000
--- a/src/dialogs/UserProfile.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#pragma once
-
-#include <QString>
-#include <QWidget>
-
-class Avatar;
-class FlatButton;
-class QLabel;
-class QListWidget;
-class Toggle;
-
-struct DeviceInfo
-{
-        QString device_id;
-        QString display_name;
-};
-
-class Proxy : public QObject
-{
-        Q_OBJECT
-
-signals:
-        void done(const QString &user_id, const std::vector<DeviceInfo> &devices);
-};
-
-namespace dialogs {
-
-class DeviceItem : public QWidget
-{
-        Q_OBJECT
-
-public:
-        explicit DeviceItem(DeviceInfo device, QWidget *parent);
-
-private:
-        DeviceInfo info_;
-
-        // Toggle *verifyToggle_;
-};
-
-class UserProfile : public QWidget
-{
-        Q_OBJECT
-public:
-        explicit UserProfile(QWidget *parent = nullptr);
-
-        void init(const QString &userId, const QString &roomId);
-
-private slots:
-        void updateDeviceList(const QString &user_id, const std::vector<DeviceInfo> &devices);
-
-private:
-        void resetToDefaults();
-
-        Avatar *avatar_;
-
-        QLabel *userIdLabel_;
-        QLabel *displayNameLabel_;
-
-        FlatButton *banBtn_;
-        FlatButton *kickBtn_;
-        FlatButton *ignoreBtn_;
-        FlatButton *startChat_;
-
-        QLabel *devicesLabel_;
-        QListWidget *devices_;
-};
-
-} // dialogs
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index f41e7712..773a5a23 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -654,9 +654,9 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
 }
 
 void
-TimelineModel::openUserProfile(QString userid) const
+TimelineModel::openUserProfile(QString userid)
 {
-        MainWindow::instance()->openUserProfile(userid, room_id_);
+        emit openProfile(new UserProfile(room_id_, userid, this));
 }
 
 void
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index f8a84f17..104a475c 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -9,7 +9,12 @@
 #include <mtxclient/http/errors.hpp>
 
 #include "CacheCryptoStructs.h"
+<<<<<<< HEAD
 #include "EventStore.h"
+=======
+#include "ReactionsModel.h"
+#include "ui/UserProfile.h"
+>>>>>>> Refactor UserProfile
 
 namespace mtx::http {
 using RequestErr = const std::optional<mtx::http::ClientError> &;
@@ -188,7 +193,7 @@ public:
         Q_INVOKABLE QString escapeEmoji(QString str) const;
         Q_INVOKABLE void viewRawMessage(QString id) const;
         Q_INVOKABLE void viewDecryptedRawMessage(QString id) const;
-        Q_INVOKABLE void openUserProfile(QString userid) const;
+        Q_INVOKABLE void openUserProfile(QString userid);
         Q_INVOKABLE void replyAction(QString id);
         Q_INVOKABLE void readReceiptsAction(QString id) const;
         Q_INVOKABLE void redactEvent(QString id);
@@ -256,8 +261,7 @@ signals:
         void replyChanged(QString reply);
         void paginationInProgressChanged(const bool);
 
-        void newMessageToSend(mtx::events::collections::TimelineEvents event);
-        void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
+        void openProfile(UserProfile *profile);
 
 private:
         void sendEncryptedMessage(const std::string txn_id, nlohmann::json content);
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 0b732232..81c8d6d3 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -16,10 +16,9 @@
 #include "dialogs/ImageOverlay.h"
 #include "emoji/EmojiModel.h"
 #include "emoji/Provider.h"
-#include "src/ui/UserProfile.h"
-#include "src/ui/UserProfileModel.h"
 
 Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
+Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
 
 namespace msgs = mtx::events::msg;
 
@@ -109,15 +108,28 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
                                          0,
                                          "MtxEvent",
                                          "Can't instantiate enum!");
+        qmlRegisterUncreatableMetaObject(verification::staticMetaObject,
+                                         "im.nheko",
+                                         1,
+                                         0,
+                                         "VerificationStatus",
+                                         "Can't instantiate enum!");
+
         qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
         qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
         qmlRegisterType<DeviceVerificationFlow>("im.nheko", 1, 0, "DeviceVerificationFlow");
-        qmlRegisterType<UserProfileModel>("im.nheko", 1, 0, "UserProfileModel");
-        qmlRegisterType<UserProfile>("im.nheko", 1, 0, "UserProfileList");
+        qmlRegisterUncreatableType<UserProfile>(
+          "im.nheko",
+          1,
+          0,
+          "UserProfileModel",
+          "UserProfile needs to be instantiated on the C++ side");
         qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", this);
         qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", settings.data());
 
         qRegisterMetaType<mtx::events::collections::TimelineEvents>();
+        qRegisterMetaType<std::vector<DeviceInfo>>();
+
         qmlRegisterType<emoji::EmojiModel>("im.nheko.EmojiModel", 1, 0, "EmojiModel");
         qmlRegisterType<emoji::EmojiProxyModel>("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel");
         qmlRegisterUncreatableType<QAbstractItemModel>(
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 8c6fb8e4..fde0044b 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -5,47 +5,72 @@
 #include "Utils.h"
 #include "mtx/responses/crypto.hpp"
 
-#include <iostream> // only for debugging
+UserProfile::UserProfile(QString roomid, QString userid, QObject *parent)
+  : QObject(parent)
+  , roomid_(roomid)
+  , userid_(userid)
+{
+        fetchDeviceList(this->userid_);
+}
 
-Q_DECLARE_METATYPE(UserProfile::Status)
+QHash<int, QByteArray>
+DeviceInfoModel::roleNames() const
+{
+        return {
+          {DeviceId, "deviceId"},
+          {DeviceName, "deviceName"},
+          {VerificationStatus, "verificationStatus"},
+        };
+}
 
-UserProfile::UserProfile(QObject *parent)
-  : QObject(parent)
+QVariant
+DeviceInfoModel::data(const QModelIndex &index, int role) const
 {
-        qRegisterMetaType<UserProfile::Status>();
-        connect(
-          this, &UserProfile::updateDeviceList, this, [this]() { fetchDeviceList(this->userId); });
-        connect(
-          this,
-          &UserProfile::appendDeviceList,
-          this,
-          [this](QString device_id, QString device_name, UserProfile::Status verification_status) {
-                  this->deviceList.push_back(
-                    DeviceInfo{device_id, device_name, verification_status});
-          });
+        if (!index.isValid() || index.row() >= (int)deviceList_.size() || index.row() < 0)
+                return {};
+
+        switch (role) {
+        case DeviceId:
+                return deviceList_[index.row()].device_id;
+        case DeviceName:
+                return deviceList_[index.row()].display_name;
+        case VerificationStatus:
+                return QVariant::fromValue(deviceList_[index.row()].verification_status);
+        default:
+                return {};
+        }
 }
 
-std::vector<DeviceInfo>
-UserProfile::getDeviceList()
+void
+DeviceInfoModel::reset(const std::vector<DeviceInfo> &deviceList)
 {
-        return this->deviceList;
+        beginResetModel();
+        this->deviceList_ = std::move(deviceList);
+        endResetModel();
+}
+
+DeviceInfoModel *
+UserProfile::deviceList()
+{
+        return &this->deviceList_;
 }
 
 QString
-UserProfile::getUserId()
+UserProfile::userid()
 {
-        return this->userId;
+        return this->userid_;
 }
 
-void
-UserProfile::setUserId(const QString &user_id)
+QString
+UserProfile::displayName()
 {
-        if (this->userId != userId)
-                return;
-        else {
-                this->userId = user_id;
-                emit UserProfile::userIdChanged();
-        }
+        return cache::displayName(roomid_, userid_);
+}
+
+QString
+UserProfile::avatarUrl()
+{
+        return cache::avatarUrl(roomid_, userid_);
 }
 
 void
@@ -74,27 +99,27 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
                 auto device = d.second;
 
                 // TODO: Verify signatures and ignore those that don't pass.
-                UserProfile::Status verified = UserProfile::Status::UNVERIFIED;
+                verification::Status verified = verification::Status::UNVERIFIED;
                 if (cross_verified.has_value()) {
                         if (std::find(cross_verified->begin(), cross_verified->end(), d.first) !=
                             cross_verified->end())
-                                verified = UserProfile::Status::VERIFIED;
+                                verified = verification::Status::VERIFIED;
                 } else if (device_verified.has_value()) {
                         if (std::find(device_verified->device_verified.begin(),
                                       device_verified->device_verified.end(),
                                       d.first) != device_verified->device_verified.end())
-                                verified = UserProfile::Status::VERIFIED;
+                                verified = verification::Status::VERIFIED;
                 } else if (device_verified.has_value()) {
                         if (std::find(device_verified->device_blocked.begin(),
                                       device_verified->device_blocked.end(),
                                       d.first) != device_verified->device_blocked.end())
-                                verified = UserProfile::Status::BLOCKED;
+                                verified = verification::Status::BLOCKED;
                 }
 
-                emit UserProfile::appendDeviceList(
-                  QString::fromStdString(d.first),
-                  QString::fromStdString(device.unsigned_info.device_display_name),
-                  verified);
+                deviceInfo.push_back(
+                  {QString::fromStdString(d.first),
+                   QString::fromStdString(device.unsigned_info.device_display_name),
+                   verified});
         }
 
         // std::sort(
@@ -102,8 +127,7 @@ UserProfile::callback_fn(const mtx::responses::QueryKeys &res,
         //           return a.device_id > b.device_id;
         //   });
 
-        this->deviceList = std::move(deviceInfo);
-        emit UserProfile::deviceListUpdated();
+        this->deviceList_.queueReset(std::move(deviceInfo));
 }
 
 void
@@ -130,7 +154,7 @@ UserProfile::fetchDeviceList(const QString &userID)
 void
 UserProfile::banUser()
 {
-        ChatPage::instance()->banUser(this->userId, "");
+        ChatPage::instance()->banUser(this->userid_, "");
 }
 
 // void ignoreUser(){
@@ -140,7 +164,7 @@ UserProfile::banUser()
 void
 UserProfile::kickUser()
 {
-        ChatPage::instance()->kickUser(this->userId, "");
+        ChatPage::instance()->kickUser(this->userid_, "");
 }
 
 void
@@ -149,7 +173,7 @@ UserProfile::startChat()
         mtx::requests::CreateRoom req;
         req.preset     = mtx::requests::Preset::PrivateChat;
         req.visibility = mtx::requests::Visibility::Private;
-        if (utils::localUser() != this->userId)
-                req.invite = {this->userId.toStdString()};
+        if (utils::localUser() != this->userid_)
+                req.invite = {this->userid_.toStdString()};
         emit ChatPage::instance()->createRoom(req);
 }
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 1725b961..38002fff 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -1,34 +1,92 @@
 #pragma once
 
+#include <QAbstractListModel>
 #include <QObject>
 #include <QString>
 #include <QVector>
 
 #include "MatrixClient.h"
 
-class DeviceInfo;
+namespace verification {
+Q_NAMESPACE
 
-class UserProfile : public QObject
+enum Status
+{
+        VERIFIED,
+        UNVERIFIED,
+        BLOCKED
+};
+Q_ENUM_NS(Status)
+}
+
+class DeviceInfo
+{
+public:
+        DeviceInfo(const QString deviceID,
+                   const QString displayName,
+                   verification::Status verification_status_)
+          : device_id(deviceID)
+          , display_name(displayName)
+          , verification_status(verification_status_)
+        {}
+        DeviceInfo()
+          : verification_status(verification::UNVERIFIED)
+        {}
+
+        QString device_id;
+        QString display_name;
+
+        verification::Status verification_status;
+};
+
+class DeviceInfoModel : public QAbstractListModel
 {
         Q_OBJECT
-        Q_PROPERTY(QString userId READ getUserId WRITE setUserId NOTIFY userIdChanged)
-        Q_PROPERTY(std::vector<DeviceInfo> deviceList READ getDeviceList NOTIFY deviceListUpdated)
 public:
-        // constructor
-        explicit UserProfile(QObject *parent = 0);
-        // getters
-        std::vector<DeviceInfo> getDeviceList();
-        QString getUserId();
-        // setters
-        void setUserId(const QString &userId);
-
-        enum Status
+        enum Roles
         {
-                VERIFIED,
-                UNVERIFIED,
-                BLOCKED
+                DeviceId,
+                DeviceName,
+                VerificationStatus,
         };
-        Q_ENUM(Status)
+
+        explicit DeviceInfoModel(QObject *parent = nullptr)
+        {
+                (void)parent;
+                connect(this, &DeviceInfoModel::queueReset, this, &DeviceInfoModel::reset);
+        };
+        QHash<int, QByteArray> roleNames() const override;
+        int rowCount(const QModelIndex &parent = QModelIndex()) const
+        {
+                (void)parent;
+                return (int)deviceList_.size();
+        }
+        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+signals:
+        void queueReset(const std::vector<DeviceInfo> &deviceList);
+public slots:
+        void reset(const std::vector<DeviceInfo> &deviceList);
+
+private:
+        std::vector<DeviceInfo> deviceList_;
+};
+
+class UserProfile : public QObject
+{
+        Q_OBJECT
+        Q_PROPERTY(QString displayName READ displayName CONSTANT)
+        Q_PROPERTY(QString userid READ userid CONSTANT)
+        Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
+        Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
+public:
+        UserProfile(QString roomid, QString userid, QObject *parent = 0);
+
+        DeviceInfoModel *deviceList();
+
+        QString userid();
+        QString displayName();
+        QString avatarUrl();
 
         void fetchDeviceList(const QString &userID);
         Q_INVOKABLE void banUser();
@@ -36,37 +94,13 @@ public:
         Q_INVOKABLE void kickUser();
         Q_INVOKABLE void startChat();
 
-signals:
-        void userIdChanged();
-        void deviceListUpdated();
-        void updateDeviceList();
-        void appendDeviceList(const QString device_id,
-                              const QString device_naem,
-                              const UserProfile::Status verification_status);
-
 private:
-        std::vector<DeviceInfo> deviceList;
-        QString userId;
+        QString roomid_, userid_;
         std::optional<std::string> cross_verified;
+        DeviceInfoModel deviceList_;
 
         void callback_fn(const mtx::responses::QueryKeys &res,
                          mtx::http::RequestErr err,
                          std::string user_id,
                          std::optional<std::vector<std::string>> cross_verified);
 };
-
-class DeviceInfo
-{
-public:
-        DeviceInfo(const QString deviceID,
-                   const QString displayName,
-                   UserProfile::Status verification_status_)
-          : device_id(deviceID)
-          , display_name(displayName)
-          , verification_status(verification_status_)
-        {}
-
-        QString device_id;
-        QString display_name;
-        UserProfile::Status verification_status;
-};
\ No newline at end of file
diff --git a/src/ui/UserProfileModel.cpp b/src/ui/UserProfileModel.cpp
deleted file mode 100644
index 3fa8fe2d..00000000
--- a/src/ui/UserProfileModel.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "UserProfileModel.h"
-#include <QModelIndex>
-
-UserProfileModel::UserProfileModel(QObject *parent)
-  : QAbstractListModel(parent)
-  , deviceList(nullptr)
-{
-        this->deviceList = new UserProfile(this);
-
-        connect(this->deviceList, &UserProfile::userIdChanged, this, [this]() {
-                emit this->deviceList->updateDeviceList();
-        });
-        connect(this->deviceList, &UserProfile::deviceListUpdated, this, [this]() {
-                beginResetModel();
-                this->beginInsertRows(
-                  QModelIndex(), 0, this->deviceList->getDeviceList().size() - 1);
-                this->endInsertRows();
-                endResetModel();
-        });
-}
-
-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() &&
-            static_cast<int>(this->deviceList->getDeviceList().size()) <= index.row())
-                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);
-        case VERIFIED_STATUS:
-                return device.verification_status;
-        }
-        return QVariant();
-}
-
-QHash<int, QByteArray>
-UserProfileModel::roleNames() const
-{
-        QHash<int, QByteArray> names;
-        names[DEVICEID]        = "deviceID";
-        names[DISPLAYNAME]     = "displayName";
-        names[VERIFIED_STATUS] = "verified_status";
-        return names;
-}
-
-UserProfile *
-UserProfileModel::getList() const
-{
-        return (this->deviceList);
-}
diff --git a/src/ui/UserProfileModel.h b/src/ui/UserProfileModel.h
deleted file mode 100644
index ba7a2525..00000000
--- a/src/ui/UserProfileModel.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include "UserProfile.h"
-#include <QAbstractListModel>
-
-class UserProfile; // forward declaration of the class UserProfile
-
-class UserProfileModel : public QAbstractListModel
-{
-        Q_OBJECT
-        Q_PROPERTY(UserProfile *deviceList READ getList)
-
-public:
-        explicit UserProfileModel(QObject *parent = nullptr);
-
-        enum
-        {
-                DEVICEID,
-                DISPLAYNAME,
-                VERIFIED_STATUS
-        };
-        UserProfile *getList() const;
-
-        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-        QVariant data(const QModelIndex &index, int role) const override;
-        virtual QHash<int, QByteArray> roleNames() const override;
-
-private:
-        UserProfile *deviceList;
-};
\ No newline at end of file