Show device list in user profile & add option to create 1-1 chat

This commit is contained in:
Konstantinos Sideris 2018-07-20 16:15:50 +03:00
parent d7e5171bfa
commit 83008f44e4
15 changed files with 162 additions and 21 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 B

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

After

Width:  |  Height:  |  Size: 1,005 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 892 B

View file

@ -80,6 +80,7 @@ public:
public slots:
void leaveRoom(const QString &room_id);
void createRoom(const mtx::requests::CreateRoom &req);
signals:
void connectionLost();
@ -159,7 +160,6 @@ private slots:
void dropToLoginPage(const QString &msg);
void joinRoom(const QString &room);
void createRoom(const mtx::requests::CreateRoom &req);
void sendTypingNotifications();
private:

View file

@ -317,6 +317,7 @@ MainWindow::openUserProfile(const QString &user_id, const QString &room_id)
userProfileModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, userProfileDialog_.data()));
userProfileModal_->setContentAlignment(Qt::AlignTop | Qt::AlignHCenter);
userProfileModal_->show();
}
@ -394,7 +395,6 @@ MainWindow::showOverlayProgressBar()
progressModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, spinner_.data()),
[](OverlayModal *modal) { modal->deleteLater(); });
progressModal_->setContentAlignment(Qt::AlignCenter);
progressModal_->setColor(QColor(30, 30, 30));
progressModal_->setDismissible(false);
progressModal_->show();

View file

@ -2,11 +2,19 @@
#include <QApplication>
#include <QDesktopWidget>
#include <QSettings>
#include <variant.hpp>
using TimelineEvent = mtx::events::collections::TimelineEvents;
QString
utils::localUser()
{
QSettings settings;
return settings.value("auth/user_id").toString();
}
QString
utils::descriptiveTime(const QDateTime &then)
{

View file

@ -15,6 +15,9 @@ namespace utils {
using TimelineEvent = mtx::events::collections::TimelineEvents;
QString
localUser();
//! Human friendly timestamp representation.
QString
descriptiveTime(const QDateTime &then);

View file

@ -8,6 +8,8 @@
#include "AvatarProvider.h"
#include "Cache.h"
#include "ChatPage.h"
#include "MatrixClient.h"
#include "Utils.h"
#include "dialogs/UserProfile.h"
#include "ui/Avatar.h"
@ -17,10 +19,25 @@ using namespace dialogs;
constexpr int BUTTON_SIZE = 36;
DeviceItem::DeviceItem(QWidget *parent, QString deviceName)
DeviceItem::DeviceItem(DeviceInfo device, QWidget *parent)
: QWidget(parent)
, name_(deviceName)
{}
, 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)
@ -34,6 +51,7 @@ UserProfile::UserProfile(QWidget *parent)
banBtn_->setIcon(banIcon);
banBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
banBtn_->setToolTip(tr("Ban the user from the room"));
banBtn_->setDisabled(true); // Not used yet.
ignoreIcon.addFile(":/icons/icons/ui/volume-off-indicator.png");
ignoreBtn_ = new FlatButton(this);
@ -42,6 +60,7 @@ UserProfile::UserProfile(QWidget *parent)
ignoreBtn_->setIcon(ignoreIcon);
ignoreBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
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);
@ -50,6 +69,7 @@ UserProfile::UserProfile(QWidget *parent)
kickBtn_->setIcon(kickIcon);
kickBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
kickBtn_->setToolTip(tr("Kick the user from the room"));
kickBtn_->setDisabled(true); // Not used yet.
startChatIcon.addFile(":/icons/icons/ui/black-bubble-speech.png");
startChat_ = new FlatButton(this);
@ -59,21 +79,34 @@ UserProfile::UserProfile(QWidget *parent)
startChat_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
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);
});
// Button line
auto btnLayout = new QHBoxLayout;
btnLayout->addStretch(1);
btnLayout->addWidget(startChat_);
btnLayout->addWidget(ignoreBtn_);
// TODO: check if the user has enough power level given the room_id
// in which the profile was opened.
btnLayout->addWidget(kickBtn_);
btnLayout->addWidget(banBtn_);
btnLayout->addStretch(1);
btnLayout->setSpacing(8);
btnLayout->setMargin(0);
avatar_ = new Avatar(this);
avatar_->setLetter("X");
avatar_->setSize(148);
avatar_->setSize(128);
QFont font;
font.setPointSizeF(font.pointSizeF() * 2);
@ -90,10 +123,26 @@ UserProfile::UserProfile(QWidget *parent)
textLayout->setSpacing(4);
textLayout->setMargin(0);
devices_ = new QListWidget{this};
devices_->setFrameStyle(QFrame::NoFrame);
devices_->setSelectionMode(QAbstractItemView::NoSelection);
devices_->setAttribute(Qt::WA_MacShowFocusRect, 0);
devices_->setSpacing(5);
devices_->hide();
QFont descriptionLabelFont;
descriptionLabelFont.setWeight(65);
devicesLabel_ = new QLabel(tr("Devices").toUpper(), this);
devicesLabel_->setFont(descriptionLabelFont);
devicesLabel_->hide();
auto vlayout = new QVBoxLayout{this};
vlayout->addWidget(avatar_);
vlayout->addLayout(textLayout);
vlayout->addLayout(btnLayout);
vlayout->addWidget(devicesLabel_, Qt::AlignLeft);
vlayout->addWidget(devices_);
vlayout->setAlignment(avatar_, Qt::AlignCenter | Qt::AlignTop);
vlayout->setAlignment(userIdLabel_, Qt::AlignCenter | Qt::AlignTop);
@ -107,6 +156,10 @@ UserProfile::UserProfile(QWidget *parent)
vlayout->setSpacing(15);
vlayout->setContentsMargins(20, 40, 20, 20);
qRegisterMetaType<std::vector<DeviceInfo>>();
connect(this, &UserProfile::devicesRetrieved, this, &UserProfile::updateDeviceList);
}
void
@ -121,13 +174,7 @@ UserProfile::init(const QString &userId, const QString &roomId)
AvatarProvider::resolve(
roomId, userId, this, [this](const QImage &img) { avatar_->setImage(img); });
QSettings settings;
auto localUser = settings.value("auth/user_id").toString();
if (localUser == userId) {
qDebug() << "the local user should have edit rights on avatar & display name";
// TODO: click on display name & avatar to change.
}
auto localUser = utils::localUser();
try {
bool hasMemberRights =
@ -141,6 +188,75 @@ UserProfile::init(const QString &userId, const QString &roomId)
} 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()] = {};
http::client()->query_keys(
req,
[user_id = userId.toStdString(), this](const mtx::responses::QueryKeys &res,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {} {}",
err->matrix_error.error,
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 devicesRetrieved(deviceInfo);
});
}
void
UserProfile::updateDeviceList(const std::vector<DeviceInfo> &devices)
{
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();
}
void

View file

@ -7,6 +7,15 @@ class Avatar;
class FlatButton;
class QLabel;
class QListWidget;
class Toggle;
struct DeviceInfo
{
QString device_id;
QString display_name;
};
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
namespace dialogs {
@ -15,10 +24,10 @@ class DeviceItem : public QWidget
Q_OBJECT
public:
explicit DeviceItem(QWidget *parent, QString deviceName);
explicit DeviceItem(DeviceInfo device, QWidget *parent);
private:
QString name_;
DeviceInfo info_;
// Toggle *verifyToggle_;
};
@ -34,12 +43,15 @@ public:
protected:
void paintEvent(QPaintEvent *) override;
signals:
void devicesRetrieved(const std::vector<DeviceInfo> &devices);
private slots:
void updateDeviceList(const std::vector<DeviceInfo> &devices);
private:
Avatar *avatar_;
QString displayName_;
QString userId_;
QLabel *userIdLabel_;
QLabel *displayNameLabel_;
@ -48,6 +60,8 @@ private:
FlatButton *ignoreBtn_;
FlatButton *startChat_;
QLabel *devicesLabel_;
QListWidget *devices_;
};
} // dialogs

View file

@ -29,7 +29,7 @@ OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
layout_->addWidget(content);
layout_->setSpacing(0);
layout_->setContentsMargins(10, 40, 10, 20);
setContentAlignment(Qt::AlignTop | Qt::AlignHCenter);
setContentAlignment(Qt::AlignCenter);
content->setFocus();
}