mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 11:00:48 +03:00
Refactor UserProfile
This commit is contained in:
parent
ac1fbbb69f
commit
08028d5c57
14 changed files with 366 additions and 783 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -8,14 +8,12 @@ import im.nheko 1.0
|
|||
import "./device-verification"
|
||||
|
||||
ApplicationWindow{
|
||||
property var user_data
|
||||
property var avatarUrl
|
||||
property var colors: currentActivePalette
|
||||
property var profile
|
||||
|
||||
id:userProfileDialog
|
||||
id: userProfileDialog
|
||||
height: 650
|
||||
width: 420
|
||||
modality:Qt.WindowModal
|
||||
modality: Qt.WindowModal
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
palette: colors
|
||||
|
||||
|
@ -40,41 +38,38 @@ ApplicationWindow{
|
|||
width: userProfileDialog.width
|
||||
spacing: 10
|
||||
|
||||
Avatar{
|
||||
id: userProfileAvatar
|
||||
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
Avatar {
|
||||
url: profile.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
height: 130
|
||||
width: 130
|
||||
displayName: user_data.userName
|
||||
userid: user_data.userId
|
||||
displayName: profile.displayName
|
||||
userid: profile.userid
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.margins : {
|
||||
top: 10
|
||||
}
|
||||
}
|
||||
|
||||
Label{
|
||||
id: userProfileName
|
||||
text: user_data.userName
|
||||
Label {
|
||||
text: profile.displayName
|
||||
fontSizeMode: Text.HorizontalFit
|
||||
font.pixelSize: 20
|
||||
color:TimelineManager.userColor(user_data.userId, colors.window)
|
||||
color: TimelineManager.userColor(profile.userid, colors.window)
|
||||
font.bold: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Label{
|
||||
id: matrixUserID
|
||||
text: user_data.userId
|
||||
Label {
|
||||
text: profile.userid
|
||||
fontSizeMode: Text.HorizontalFit
|
||||
font.pixelSize: 15
|
||||
color:colors.text
|
||||
color: colors.text
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
RowLayout{
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
ImageButton{
|
||||
ImageButton {
|
||||
image:":/icons/icons/ui/do-not-disturb-rounded-sign.png"
|
||||
Layout.margins: {
|
||||
left: 5
|
||||
|
@ -83,7 +78,7 @@ ApplicationWindow{
|
|||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Ban the user")
|
||||
onClicked : {
|
||||
modelDeviceList.deviceList.banUser()
|
||||
profile.banUser()
|
||||
}
|
||||
}
|
||||
// ImageButton{
|
||||
|
@ -95,7 +90,7 @@ ApplicationWindow{
|
|||
// ToolTip.visible: hovered
|
||||
// ToolTip.text: qsTr("Ignore messages from this user")
|
||||
// onClicked : {
|
||||
// modelDeviceList.deviceList.ignoreUser()
|
||||
// profile.ignoreUser()
|
||||
// }
|
||||
// }
|
||||
ImageButton{
|
||||
|
@ -107,7 +102,7 @@ ApplicationWindow{
|
|||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Start a private chat")
|
||||
onClicked : {
|
||||
modelDeviceList.deviceList.startChat()
|
||||
profile.startChat()
|
||||
}
|
||||
}
|
||||
ImageButton{
|
||||
|
@ -119,7 +114,7 @@ ApplicationWindow{
|
|||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Kick the user")
|
||||
onClicked : {
|
||||
modelDeviceList.deviceList.kickUser()
|
||||
profile.kickUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,10 +131,7 @@ ApplicationWindow{
|
|||
clip: true
|
||||
spacing: 4
|
||||
|
||||
model: UserProfileModel{
|
||||
id: modelDeviceList
|
||||
deviceList.userId : user_data.userId
|
||||
}
|
||||
model: profile.deviceList
|
||||
|
||||
delegate: RowLayout{
|
||||
width: parent.width
|
||||
|
@ -153,20 +145,20 @@ ApplicationWindow{
|
|||
color: colors.text
|
||||
font.bold: true
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: deviceID
|
||||
text: model.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: (model.verificationStatus == VerificationStatus.VERIFIED?"V":(model.verificationStatus == VerificationStatus.UNVERIFIED?"NV":"B"))
|
||||
}
|
||||
}
|
||||
Text{
|
||||
Layout.fillWidth: true
|
||||
color:colors.text
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: displayName
|
||||
text: model.deviceName
|
||||
}
|
||||
}
|
||||
Button{
|
||||
|
@ -174,10 +166,9 @@ ApplicationWindow{
|
|||
text:"Verify"
|
||||
onClicked: {
|
||||
var newFlow = deviceVerificationFlow.createObject(userProfileDialog,
|
||||
{userId : user_data.userId,sender: true,deviceId : model.deviceID});
|
||||
{userId : profile.userid, sender: true, deviceId : model.deviceID});
|
||||
deviceVerificationList.add(newFlow.tranId);
|
||||
var dialog = deviceVerificationDialog.createObject(userProfileDialog,
|
||||
{flow: newFlow});
|
||||
var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow});
|
||||
dialog.show();
|
||||
}
|
||||
Layout.margins:{
|
||||
|
|
|
@ -317,15 +317,6 @@ MainWindow::hasActiveUser()
|
|||
settings.contains("auth/user_id");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -5,47 +5,72 @@
|
|||
#include "Utils.h"
|
||||
#include "mtx/responses/crypto.hpp"
|
||||
|
||||
#include <iostream> // only for debugging
|
||||
|
||||
Q_DECLARE_METATYPE(UserProfile::Status)
|
||||
|
||||
UserProfile::UserProfile(QObject *parent)
|
||||
UserProfile::UserProfile(QString roomid, QString userid, QObject *parent)
|
||||
: QObject(parent)
|
||||
, roomid_(roomid)
|
||||
, userid_(userid)
|
||||
{
|
||||
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});
|
||||
});
|
||||
fetchDeviceList(this->userid_);
|
||||
}
|
||||
|
||||
std::vector<DeviceInfo>
|
||||
UserProfile::getDeviceList()
|
||||
QHash<int, QByteArray>
|
||||
DeviceInfoModel::roleNames() const
|
||||
{
|
||||
return this->deviceList;
|
||||
return {
|
||||
{DeviceId, "deviceId"},
|
||||
{DeviceName, "deviceName"},
|
||||
{VerificationStatus, "verificationStatus"},
|
||||
};
|
||||
}
|
||||
|
||||
QString
|
||||
UserProfile::getUserId()
|
||||
QVariant
|
||||
DeviceInfoModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return this->userId;
|
||||
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 {};
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UserProfile::setUserId(const QString &user_id)
|
||||
DeviceInfoModel::reset(const std::vector<DeviceInfo> &deviceList)
|
||||
{
|
||||
if (this->userId != userId)
|
||||
return;
|
||||
else {
|
||||
this->userId = user_id;
|
||||
emit UserProfile::userIdChanged();
|
||||
}
|
||||
beginResetModel();
|
||||
this->deviceList_ = std::move(deviceList);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
DeviceInfoModel *
|
||||
UserProfile::deviceList()
|
||||
{
|
||||
return &this->deviceList_;
|
||||
}
|
||||
|
||||
QString
|
||||
UserProfile::userid()
|
||||
{
|
||||
return this->userid_;
|
||||
}
|
||||
|
||||
QString
|
||||
UserProfile::displayName()
|
||||
{
|
||||
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),
|
||||
deviceInfo.push_back(
|
||||
{QString::fromStdString(d.first),
|
||||
QString::fromStdString(device.unsigned_info.device_display_name),
|
||||
verified);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,34 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "MatrixClient.h"
|
||||
|
||||
class DeviceInfo;
|
||||
namespace verification {
|
||||
Q_NAMESPACE
|
||||
|
||||
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
|
||||
public:
|
||||
enum Roles
|
||||
{
|
||||
DeviceId,
|
||||
DeviceName,
|
||||
VerificationStatus,
|
||||
};
|
||||
|
||||
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 userId READ getUserId WRITE setUserId NOTIFY userIdChanged)
|
||||
Q_PROPERTY(std::vector<DeviceInfo> deviceList READ getDeviceList NOTIFY deviceListUpdated)
|
||||
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:
|
||||
// constructor
|
||||
explicit UserProfile(QObject *parent = 0);
|
||||
// getters
|
||||
std::vector<DeviceInfo> getDeviceList();
|
||||
QString getUserId();
|
||||
// setters
|
||||
void setUserId(const QString &userId);
|
||||
UserProfile(QString roomid, QString userid, QObject *parent = 0);
|
||||
|
||||
enum Status
|
||||
{
|
||||
VERIFIED,
|
||||
UNVERIFIED,
|
||||
BLOCKED
|
||||
};
|
||||
Q_ENUM(Status)
|
||||
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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
Loading…
Reference in a new issue