diff --git a/src/dialogs/UserProfile.cpp b/src/dialogs/UserProfile.cpp deleted file mode 100644 index 086dbb40..00000000 --- a/src/dialogs/UserProfile.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#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) - -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()}; - - if (QMessageBox::question( - this, - tr("Confirm DM"), - tr("Do you really want to invite %1 (%2) to a direct chat?") - .arg(cache::displayName(roomId_, user_id)) - .arg(user_id)) != QMessageBox::Yes) - return; - - 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>(); - - 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(); - - this->roomId_ = roomId; - - 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(); - 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(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; - 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 &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 8129fdcf..00000000 --- a/src/dialogs/UserProfile.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include - -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 &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 &devices); - -private: - void resetToDefaults(); - - Avatar *avatar_; - QString roomId_; - - QLabel *userIdLabel_; - QLabel *displayNameLabel_; - - FlatButton *banBtn_; - FlatButton *kickBtn_; - FlatButton *ignoreBtn_; - FlatButton *startChat_; - - QLabel *devicesLabel_; - QListWidget *devices_; -}; - -} // dialogs diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp index b3784843..37fe142a 100644 --- a/src/popups/PopupItem.cpp +++ b/src/popups/PopupItem.cpp @@ -37,68 +37,6 @@ PopupItem::paintEvent(QPaintEvent *) p.fillRect(rect(), hoverColor_); } -UserItem::UserItem(QWidget *parent) - : PopupItem(parent) -{ - userName_ = new QLabel("Placeholder", this); - avatar_->setLetter("P"); - topLayout_->addWidget(avatar_); - topLayout_->addWidget(userName_, 1); -} - -UserItem::UserItem(QWidget *parent, const QString &user_id) - : PopupItem(parent) - , userId_{user_id} -{ - auto displayName = cache::displayName(ChatPage::instance()->currentRoom(), userId_); - - avatar_->setLetter(utils::firstChar(displayName)); - - // If it's a matrix id we use the second letter. - if (displayName.size() > 1 && displayName.at(0) == '@') - avatar_->setLetter(QChar(displayName.at(1))); - - userName_ = new QLabel(displayName, this); - - topLayout_->addWidget(avatar_); - topLayout_->addWidget(userName_, 1); - - resolveAvatar(user_id); -} - -void -UserItem::updateItem(const QString &user_id) -{ - userId_ = user_id; - - auto displayName = cache::displayName(ChatPage::instance()->currentRoom(), userId_); - - // If it's a matrix id we use the second letter. - if (displayName.size() > 1 && displayName.at(0) == '@') - avatar_->setLetter(QChar(displayName.at(1))); - else - avatar_->setLetter(utils::firstChar(displayName)); - - userName_->setText(displayName); - resolveAvatar(user_id); -} - -void -UserItem::resolveAvatar(const QString &user_id) -{ - avatar_->setImage(ChatPage::instance()->currentRoom(), user_id); -} - -void -UserItem::mousePressEvent(QMouseEvent *event) -{ - if (event->buttons() != Qt::RightButton) - emit clicked( - cache::displayName(ChatPage::instance()->currentRoom(), selectedText())); - - QWidget::mousePressEvent(event); -} - RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res) : PopupItem(parent) , roomId_{QString::fromStdString(res.room_id)} diff --git a/src/popups/PopupItem.h b/src/popups/PopupItem.h index 17a4f6bc..499d6b33 100644 --- a/src/popups/PopupItem.h +++ b/src/popups/PopupItem.h @@ -43,26 +43,6 @@ protected: bool hovering_; }; -class UserItem : public PopupItem -{ - Q_OBJECT - -public: - UserItem(QWidget *parent); - UserItem(QWidget *parent, const QString &user_id); - QString selectedText() const { return userId_; } - void updateItem(const QString &user_id); - -protected: - void mousePressEvent(QMouseEvent *event) override; - -private: - void resolveAvatar(const QString &user_id); - - QLabel *userName_; - QString userId_; -}; - class RoomItem : public PopupItem { Q_OBJECT