Create user profile modal

This commit is contained in:
Konstantinos Sideris 2018-07-20 12:02:35 +03:00
parent 5540fc0737
commit d7e5171bfa
27 changed files with 265 additions and 13 deletions

View File

@ -152,6 +152,7 @@ set(SRC_FILES
src/dialogs/MemberList.cpp src/dialogs/MemberList.cpp
src/dialogs/LeaveRoom.cpp src/dialogs/LeaveRoom.cpp
src/dialogs/Logout.cpp src/dialogs/Logout.cpp
src/dialogs/UserProfile.cpp
src/dialogs/ReadReceipts.cpp src/dialogs/ReadReceipts.cpp
src/dialogs/ReCaptcha.cpp src/dialogs/ReCaptcha.cpp
src/dialogs/RoomSettings.cpp src/dialogs/RoomSettings.cpp
@ -265,6 +266,7 @@ qt5_wrap_cpp(MOC_HEADERS
src/dialogs/MemberList.h src/dialogs/MemberList.h
src/dialogs/LeaveRoom.h src/dialogs/LeaveRoom.h
src/dialogs/Logout.h src/dialogs/Logout.h
src/dialogs/UserProfile.h
src/dialogs/ReadReceipts.h src/dialogs/ReadReceipts.h
src/dialogs/ReCaptcha.h src/dialogs/ReCaptcha.h
src/dialogs/RoomSettings.h src/dialogs/RoomSettings.h

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,5 +1,14 @@
<RCC> <RCC>
<qresource prefix="/icons"> <qresource prefix="/icons">
<file>icons/ui/volume-off-indicator.png</file>
<file>icons/ui/volume-off-indicator@2x.png</file>
<file>icons/ui/black-bubble-speech.png</file>
<file>icons/ui/black-bubble-speech@2x.png</file>
<file>icons/ui/do-not-disturb-rounded-sign.png</file>
<file>icons/ui/do-not-disturb-rounded-sign@2x.png</file>
<file>icons/ui/round-remove-button.png</file>
<file>icons/ui/round-remove-button@2x.png</file>
<file>icons/ui/double-tick-indicator.png</file> <file>icons/ui/double-tick-indicator.png</file>
<file>icons/ui/double-tick-indicator@2x.png</file> <file>icons/ui/double-tick-indicator@2x.png</file>
<file>icons/ui/lock.png</file> <file>icons/ui/lock.png</file>

View File

@ -147,6 +147,7 @@ dialogs--ReadReceipts,
dialogs--JoinRoom, dialogs--JoinRoom,
dialogs--MemberList, dialogs--MemberList,
dialogs--PreviewUploadOverlay, dialogs--PreviewUploadOverlay,
dialogs--UserProfile,
dialogs--CreateRoom > QLineEdit, dialogs--CreateRoom > QLineEdit,
dialogs--InviteUsers > QLineEdit, dialogs--InviteUsers > QLineEdit,
EditModal, EditModal,

View File

@ -149,10 +149,11 @@ dialogs--ReadReceipts,
dialogs--MemberList, dialogs--MemberList,
dialogs--JoinRoom, dialogs--JoinRoom,
dialogs--PreviewUploadOverlay, dialogs--PreviewUploadOverlay,
dialogs--UserProfile,
EditModal, EditModal,
QListWidget { QListWidget {
background-color: white; background-color: white;
color: #333; color: #495057;
} }
TopSection { TopSection {

View File

@ -50,6 +50,8 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
[callback](const QByteArray &data) { callback(QImage::fromData(data)); }); [callback](const QByteArray &data) { callback(QImage::fromData(data)); });
mtx::http::ThumbOpts opts; mtx::http::ThumbOpts opts;
opts.width = 256;
opts.height = 256;
opts.mxc_url = avatarUrl.toStdString(); opts.mxc_url = avatarUrl.toStdString();
http::client()->get_thumbnail( http::client()->get_thumbnail(

View File

@ -309,6 +309,18 @@ MainWindow::hasActiveUser()
settings.contains("auth/user_id"); settings.contains("auth/user_id");
} }
void
MainWindow::openUserProfile(const QString &user_id, const QString &room_id)
{
userProfileDialog_ = QSharedPointer<dialogs::UserProfile>(new dialogs::UserProfile(this));
userProfileDialog_->init(user_id, room_id);
userProfileModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, userProfileDialog_.data()));
userProfileModal_->show();
}
void void
MainWindow::openRoomSettings(const QString &room_id) MainWindow::openRoomSettings(const QString &room_id)
{ {
@ -382,6 +394,7 @@ MainWindow::showOverlayProgressBar()
progressModal_ = progressModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, spinner_.data()), QSharedPointer<OverlayModal>(new OverlayModal(this, spinner_.data()),
[](OverlayModal *modal) { modal->deleteLater(); }); [](OverlayModal *modal) { modal->deleteLater(); });
progressModal_->setContentAlignment(Qt::AlignCenter);
progressModal_->setColor(QColor(30, 30, 30)); progressModal_->setColor(QColor(30, 30, 30));
progressModal_->setDismissible(false); progressModal_->setDismissible(false);
progressModal_->show(); progressModal_->show();

View File

@ -28,6 +28,7 @@
#include "RegisterPage.h" #include "RegisterPage.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
#include "WelcomePage.h" #include "WelcomePage.h"
#include "dialogs/UserProfile.h"
class ChatPage; class ChatPage;
class LoadingIndicator; class LoadingIndicator;
@ -71,6 +72,7 @@ public:
void openLogoutDialog(std::function<void()> callback); void openLogoutDialog(std::function<void()> callback);
void openRoomSettings(const QString &room_id = ""); void openRoomSettings(const QString &room_id = "");
void openMemberListDialog(const QString &room_id = ""); void openMemberListDialog(const QString &room_id = "");
void openUserProfile(const QString &user_id, const QString &room_id);
protected: protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
@ -171,4 +173,7 @@ private:
QSharedPointer<OverlayModal> memberListModal_; QSharedPointer<OverlayModal> memberListModal_;
//! Member list dialog. //! Member list dialog.
QSharedPointer<dialogs::MemberList> memberListDialog_; QSharedPointer<dialogs::MemberList> memberListDialog_;
QSharedPointer<OverlayModal> userProfileModal_;
QSharedPointer<dialogs::UserProfile> userProfileDialog_;
}; };

153
src/dialogs/UserProfile.cpp Normal file
View File

@ -0,0 +1,153 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QListWidget>
#include <QPaintEvent>
#include <QSettings>
#include <QStyleOption>
#include <QVBoxLayout>
#include "AvatarProvider.h"
#include "Cache.h"
#include "Utils.h"
#include "dialogs/UserProfile.h"
#include "ui/Avatar.h"
#include "ui/FlatButton.h"
using namespace dialogs;
constexpr int BUTTON_SIZE = 36;
DeviceItem::DeviceItem(QWidget *parent, QString deviceName)
: QWidget(parent)
, name_(deviceName)
{}
UserProfile::UserProfile(QWidget *parent)
: QWidget(parent)
{
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_SIZE / 2);
banBtn_->setIcon(banIcon);
banBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
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_SIZE / 2);
ignoreBtn_->setIcon(ignoreIcon);
ignoreBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
ignoreBtn_->setToolTip(tr("Ignore messages from this user"));
kickIcon.addFile(":/icons/icons/ui/round-remove-button.png");
kickBtn_ = new FlatButton(this);
kickBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE);
kickBtn_->setCornerRadius(BUTTON_SIZE / 2);
kickBtn_->setIcon(kickIcon);
kickBtn_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
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_SIZE / 2);
startChat_->setIcon(startChatIcon);
startChat_->setIconSize(QSize(BUTTON_SIZE / 2, BUTTON_SIZE / 2));
startChat_->setToolTip(tr("Start a conversation"));
// Button line
auto btnLayout = new QHBoxLayout;
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->setSpacing(8);
btnLayout->setMargin(0);
avatar_ = new Avatar(this);
avatar_->setLetter("X");
avatar_->setSize(148);
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(4);
textLayout->setMargin(0);
auto vlayout = new QVBoxLayout{this};
vlayout->addWidget(avatar_);
vlayout->addLayout(textLayout);
vlayout->addLayout(btnLayout);
vlayout->setAlignment(avatar_, Qt::AlignCenter | Qt::AlignTop);
vlayout->setAlignment(userIdLabel_, Qt::AlignCenter | Qt::AlignTop);
setAutoFillBackground(true);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
setWindowModality(Qt::WindowModal);
setMinimumWidth(340);
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
vlayout->setSpacing(15);
vlayout->setContentsMargins(20, 40, 20, 20);
}
void
UserProfile::init(const QString &userId, const QString &roomId)
{
auto displayName = Cache::displayName(roomId, userId);
userIdLabel_->setText(userId);
displayNameLabel_->setText(displayName);
avatar_->setLetter(utils::firstChar(displayName));
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.
}
try {
bool hasMemberRights =
cache::client()->hasEnoughPowerLevel({mtx::events::EventType::RoomMember},
roomId.toStdString(),
localUser.toStdString());
if (!hasMemberRights) {
kickBtn_->hide();
banBtn_->hide();
}
} catch (const lmdb::error &e) {
nhlog::db()->warn("lmdb error: {}", e.what());
}
}
void
UserProfile::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

53
src/dialogs/UserProfile.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <QString>
#include <QWidget>
class Avatar;
class FlatButton;
class QLabel;
class QListWidget;
namespace dialogs {
class DeviceItem : public QWidget
{
Q_OBJECT
public:
explicit DeviceItem(QWidget *parent, QString deviceName);
private:
QString name_;
// Toggle *verifyToggle_;
};
class UserProfile : public QWidget
{
Q_OBJECT
public:
explicit UserProfile(QWidget *parent = nullptr);
void init(const QString &userId, const QString &roomId);
protected:
void paintEvent(QPaintEvent *) override;
private:
Avatar *avatar_;
QString displayName_;
QString userId_;
QLabel *userIdLabel_;
QLabel *displayNameLabel_;
FlatButton *banBtn_;
FlatButton *kickBtn_;
FlatButton *ignoreBtn_;
FlatButton *startChat_;
QListWidget *devices_;
};
} // dialogs

View File

@ -23,6 +23,7 @@
#include "ChatPage.h" #include "ChatPage.h"
#include "Config.h" #include "Config.h"
#include "Logging.h" #include "Logging.h"
#include "MainWindow.h"
#include "Olm.h" #include "Olm.h"
#include "ui/Avatar.h" #include "ui/Avatar.h"
#include "ui/Painter.h" #include "ui/Painter.h"
@ -561,6 +562,13 @@ TimelineItem::generateBody(const QString &body)
// The username/timestamp is displayed along with the message body. // The username/timestamp is displayed along with the message body.
void void
TimelineItem::generateBody(const QString &user_id, const QString &displayname, const QString &body) TimelineItem::generateBody(const QString &user_id, const QString &displayname, const QString &body)
{
generateUserName(user_id, displayname);
generateBody(body);
}
void
TimelineItem::generateUserName(const QString &user_id, const QString &displayname)
{ {
auto sender = displayname; auto sender = displayname;
@ -598,7 +606,9 @@ TimelineItem::generateBody(const QString &user_id, const QString &displayname, c
userName_->setFont(f); userName_->setFont(f);
}); });
generateBody(body); connect(filter, &UserProfileFilter::clicked, this, [this, user_id]() {
MainWindow::instance()->openUserProfile(user_id, room_id_);
});
} }
void void
@ -742,10 +752,7 @@ TimelineItem::addAvatar()
auto userid = descriptionMsg_.userid; auto userid = descriptionMsg_.userid;
auto displayName = Cache::displayName(room_id_, userid); auto displayName = Cache::displayName(room_id_, userid);
QFontMetrics fm(usernameFont_); generateUserName(userid, displayName);
userName_ = new QLabel(this);
userName_->setFont(usernameFont_);
userName_->setText(fm.elidedText(displayName, Qt::ElideRight, 500));
setupAvatarLayout(displayName); setupAvatarLayout(displayName);

View File

@ -137,13 +137,13 @@ public:
signals: signals:
void hoverOff(); void hoverOff();
void hoverOn(); void hoverOn();
void clicked();
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) bool eventFilter(QObject *obj, QEvent *event)
{ {
if (event->type() == QEvent::MouseButtonRelease) { if (event->type() == QEvent::MouseButtonRelease) {
// QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); emit clicked();
// TODO: Open user profile
return true; return true;
} else if (event->type() == QEvent::HoverLeave) { } else if (event->type() == QEvent::HoverLeave) {
emit hoverOff(); emit hoverOff();
@ -274,6 +274,7 @@ private:
void generateBody(const QString &body); void generateBody(const QString &body);
void generateBody(const QString &user_id, const QString &displayname, const QString &body); void generateBody(const QString &user_id, const QString &displayname, const QString &body);
void generateTimestamp(const QDateTime &time); void generateTimestamp(const QDateTime &time);
void generateUserName(const QString &userid, const QString &displayname);
void setupAvatarLayout(const QString &userName); void setupAvatarLayout(const QString &userName);
void setupSimpleLayout(); void setupSimpleLayout();

View File

@ -25,11 +25,11 @@ OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
, content_{content} , content_{content}
, color_{QColor(30, 30, 30, 170)} , color_{QColor(30, 30, 30, 170)}
{ {
auto layout = new QVBoxLayout(); layout_ = new QVBoxLayout(this);
layout->addWidget(content); layout_->addWidget(content);
layout->setAlignment(Qt::AlignCenter); layout_->setSpacing(0);
layout_->setContentsMargins(10, 40, 10, 20);
setLayout(layout); setContentAlignment(Qt::AlignTop | Qt::AlignHCenter);
content->setFocus(); content->setFocus();
} }

View File

@ -20,6 +20,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QMouseEvent> #include <QMouseEvent>
#include <QPaintEvent> #include <QPaintEvent>
#include <QVBoxLayout>
#include "OverlayWidget.h" #include "OverlayWidget.h"
@ -31,6 +32,8 @@ public:
void setColor(QColor color) { color_ = color; } void setColor(QColor color) { color_ = color; }
void setDismissible(bool state) { isDismissible_ = state; } void setDismissible(bool state) { isDismissible_ = state; }
void setContentAlignment(QFlags<Qt::AlignmentFlag> flag) { layout_->setAlignment(flag); }
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
@ -38,6 +41,8 @@ protected:
private: private:
QWidget *content_; QWidget *content_;
QVBoxLayout *layout_;
QColor color_; QColor color_;
//! Decides whether or not the modal can be removed by clicking into it. //! Decides whether or not the modal can be removed by clicking into it.