Add member list

This commit is contained in:
Konstantinos Sideris 2018-05-01 19:35:28 +03:00
parent 3097037c3d
commit 763330fd3c
13 changed files with 300 additions and 14 deletions

View file

@ -102,6 +102,7 @@ set(SRC_FILES
src/dialogs/PreviewUploadOverlay.cc src/dialogs/PreviewUploadOverlay.cc
src/dialogs/InviteUsers.cc src/dialogs/InviteUsers.cc
src/dialogs/JoinRoom.cc src/dialogs/JoinRoom.cc
src/dialogs/MemberList.cpp
src/dialogs/LeaveRoom.cc src/dialogs/LeaveRoom.cc
src/dialogs/Logout.cc src/dialogs/Logout.cc
src/dialogs/ReadReceipts.cc src/dialogs/ReadReceipts.cc
@ -219,6 +220,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/dialogs/PreviewUploadOverlay.h include/dialogs/PreviewUploadOverlay.h
include/dialogs/InviteUsers.h include/dialogs/InviteUsers.h
include/dialogs/JoinRoom.h include/dialogs/JoinRoom.h
include/dialogs/MemberList.hpp
include/dialogs/LeaveRoom.h include/dialogs/LeaveRoom.h
include/dialogs/Logout.h include/dialogs/Logout.h
include/dialogs/ReadReceipts.h include/dialogs/ReadReceipts.h

View file

@ -24,6 +24,13 @@
#include <lmdb++.h> #include <lmdb++.h>
#include <mtx/responses.hpp> #include <mtx/responses.hpp>
struct RoomMember
{
QString user_id;
QString display_name;
QImage avatar;
};
struct SearchResult struct SearchResult
{ {
QString user_id; QString user_id;
@ -32,6 +39,7 @@ struct SearchResult
Q_DECLARE_METATYPE(SearchResult) Q_DECLARE_METATYPE(SearchResult)
Q_DECLARE_METATYPE(QVector<SearchResult>) Q_DECLARE_METATYPE(QVector<SearchResult>)
Q_DECLARE_METATYPE(RoomMember);
//! Used to uniquely identify a list of read receipts. //! Used to uniquely identify a list of read receipts.
struct ReadReceiptKey struct ReadReceiptKey
@ -164,6 +172,11 @@ public:
lmdb::dbi &membersdb, lmdb::dbi &membersdb,
const QString &room_id); const QString &room_id);
//! Retrieve member info from a room.
std::vector<RoomMember> getMembers(const std::string &room_id,
std::size_t startIndex = 0,
std::size_t len = 30);
void saveState(const mtx::responses::Sync &res); void saveState(const mtx::responses::Sync &res);
bool isInitialized() const; bool isInitialized() const;

View file

@ -49,6 +49,7 @@ class InviteUsers;
class JoinRoom; class JoinRoom;
class LeaveRoom; class LeaveRoom;
class Logout; class Logout;
class MemberList;
class ReCaptcha; class ReCaptcha;
class RoomSettings; class RoomSettings;
} }
@ -70,6 +71,7 @@ public:
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback); void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
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 = "");
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
@ -153,4 +155,8 @@ private:
QSharedPointer<OverlayModal> roomSettingsModal_; QSharedPointer<OverlayModal> roomSettingsModal_;
//! Room settings dialog. //! Room settings dialog.
QSharedPointer<dialogs::RoomSettings> roomSettingsDialog_; QSharedPointer<dialogs::RoomSettings> roomSettingsDialog_;
//! Member list modal.
QSharedPointer<OverlayModal> memberListModal_;
//! Member list dialog.
QSharedPointer<dialogs::MemberList> memberListDialog_;
}; };

View file

@ -67,6 +67,7 @@ private:
Menu *menu_; Menu *menu_;
QAction *leaveRoom_; QAction *leaveRoom_;
QAction *roomMembers_;
QAction *roomSettings_; QAction *roomSettings_;
QAction *inviteUsers_; QAction *inviteUsers_;

View file

@ -0,0 +1,57 @@
#pragma once
#include <QFrame>
#include <QListWidget>
class Avatar;
class Cache;
class FlatButton;
class QHBoxLayout;
class QLabel;
class QVBoxLayout;
struct RoomMember;
template<class T>
class QSharedPointer;
namespace dialogs {
class MemberItem : public QWidget
{
Q_OBJECT
public:
MemberItem(const RoomMember &member, QWidget *parent);
private:
QHBoxLayout *topLayout_;
QVBoxLayout *textLayout_;
Avatar *avatar_;
QLabel *userName_;
QLabel *userId_;
};
class MemberList : public QFrame
{
Q_OBJECT
public:
MemberList(const QString &room_id, QSharedPointer<Cache> cache, QWidget *parent = nullptr);
public slots:
void addUsers(const std::vector<RoomMember> &users);
protected:
void paintEvent(QPaintEvent *event) override;
void moveButtonToBottom();
private:
QString room_id_;
QLabel *topLabel_;
QListWidget *list_;
QSharedPointer<Cache> cache_;
FlatButton *moreBtn_;
};
} // dialogs

View file

@ -140,6 +140,7 @@ dialogs--RoomSettings,
dialogs--InviteUsers, dialogs--InviteUsers,
dialogs--ReadReceipts, dialogs--ReadReceipts,
dialogs--JoinRoom, dialogs--JoinRoom,
dialogs--MemberList,
dialogs--PreviewUploadOverlay, dialogs--PreviewUploadOverlay,
dialogs--CreateRoom > QLineEdit, dialogs--CreateRoom > QLineEdit,
dialogs--InviteUsers > QLineEdit, dialogs--InviteUsers > QLineEdit,

View file

@ -141,6 +141,7 @@ dialogs--CreateRoom,
dialogs--RoomSettings, dialogs--RoomSettings,
dialogs--InviteUsers, dialogs--InviteUsers,
dialogs--ReadReceipts, dialogs--ReadReceipts,
dialogs--MemberList,
dialogs--JoinRoom, dialogs--JoinRoom,
dialogs--PreviewUploadOverlay, dialogs--PreviewUploadOverlay,
QListWidget { QListWidget {

View file

@ -1045,6 +1045,48 @@ Cache::searchUsers(const std::string &room_id, const std::string &query, std::ui
return results; return results;
} }
std::vector<RoomMember>
Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto db = getMembersDb(txn, room_id);
auto cursor = lmdb::cursor::open(txn, db);
std::size_t currentIndex = 0;
const auto endIndex = std::min(startIndex + len, db.size(txn));
std::vector<RoomMember> members;
std::string user_id, user_data;
while (cursor.get(user_id, user_data, MDB_NEXT)) {
if (currentIndex < startIndex) {
currentIndex += 1;
continue;
}
if (currentIndex >= endIndex)
break;
try {
MemberInfo tmp = json::parse(user_data);
members.emplace_back(
RoomMember{QString::fromStdString(user_id),
QString::fromStdString(tmp.name),
QImage::fromData(image(txn, tmp.avatar_url))});
} catch (const json::exception &e) {
qWarning() << e.what();
}
currentIndex += 1;
}
cursor.close();
txn.commit();
return members;
}
QHash<QString, QString> Cache::DisplayNames; QHash<QString, QString> Cache::DisplayNames;
QHash<QString, QString> Cache::AvatarUrls; QHash<QString, QString> Cache::AvatarUrls;

View file

@ -41,6 +41,7 @@
#include "dialogs/JoinRoom.h" #include "dialogs/JoinRoom.h"
#include "dialogs/LeaveRoom.h" #include "dialogs/LeaveRoom.h"
#include "dialogs/Logout.h" #include "dialogs/Logout.h"
#include "dialogs/MemberList.hpp"
#include "dialogs/RoomSettings.hpp" #include "dialogs/RoomSettings.hpp"
MainWindow *MainWindow::instance_ = nullptr; MainWindow *MainWindow::instance_ = nullptr;
@ -268,8 +269,6 @@ MainWindow::openRoomSettings(const QString &room_id)
{ {
const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : ""; const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : "";
qDebug() << "room settings" << roomToSearch;
roomSettingsDialog_ = QSharedPointer<dialogs::RoomSettings>( roomSettingsDialog_ = QSharedPointer<dialogs::RoomSettings>(
new dialogs::RoomSettings(roomToSearch, chat_page_->cache(), this)); new dialogs::RoomSettings(roomToSearch, chat_page_->cache(), this));
@ -279,11 +278,24 @@ MainWindow::openRoomSettings(const QString &room_id)
roomSettingsModal_ = roomSettingsModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, roomSettingsDialog_.data())); QSharedPointer<OverlayModal>(new OverlayModal(this, roomSettingsDialog_.data()));
roomSettingsModal_->setColor(QColor(30, 30, 30, 170));
roomSettingsModal_->show(); roomSettingsModal_->show();
} }
void
MainWindow::openMemberListDialog(const QString &room_id)
{
const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : "";
memberListDialog_ = QSharedPointer<dialogs::MemberList>(
new dialogs::MemberList(roomToSearch, chat_page_->cache(), this));
memberListModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, memberListDialog_.data()));
memberListModal_->show();
}
void void
MainWindow::openLeaveRoomDialog(const QString &room_id) MainWindow::openLeaveRoomDialog(const QString &room_id)
{ {
@ -325,6 +337,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_->setColor(QColor(30, 30, 30));
progressModal_->setDismissible(false); progressModal_->setDismissible(false);
progressModal_->show(); progressModal_->show();
} }
@ -377,7 +390,6 @@ MainWindow::openJoinRoomDialog(std::function<void(const QString &room_id)> callb
if (joinRoomModal_.isNull()) { if (joinRoomModal_.isNull()) {
joinRoomModal_ = QSharedPointer<OverlayModal>( joinRoomModal_ = QSharedPointer<OverlayModal>(
new OverlayModal(MainWindow::instance(), joinRoomDialog_.data())); new OverlayModal(MainWindow::instance(), joinRoomDialog_.data()));
joinRoomModal_->setColor(QColor(30, 30, 30, 170));
} }
joinRoomModal_->show(); joinRoomModal_->show();
@ -406,7 +418,6 @@ MainWindow::openCreateRoomDialog(
if (createRoomModal_.isNull()) { if (createRoomModal_.isNull()) {
createRoomModal_ = QSharedPointer<OverlayModal>( createRoomModal_ = QSharedPointer<OverlayModal>(
new OverlayModal(MainWindow::instance(), createRoomDialog_.data())); new OverlayModal(MainWindow::instance(), createRoomDialog_.data()));
createRoomModal_->setColor(QColor(30, 30, 30, 170));
} }
createRoomModal_->show(); createRoomModal_->show();
@ -431,7 +442,6 @@ MainWindow::openLogoutDialog(std::function<void()> callback)
if (logoutModal_.isNull()) { if (logoutModal_.isNull()) {
logoutModal_ = QSharedPointer<OverlayModal>( logoutModal_ = QSharedPointer<OverlayModal>(
new OverlayModal(MainWindow::instance(), logoutDialog_.data())); new OverlayModal(MainWindow::instance(), logoutDialog_.data()));
logoutModal_->setColor(QColor(30, 30, 30, 170));
} }
logoutModal_->show(); logoutModal_->show();

View file

@ -90,6 +90,11 @@ TopRoomBar::TopRoomBar(QWidget *parent)
[this](const QStringList &invitees) { emit inviteUsers(invitees); }); [this](const QStringList &invitees) { emit inviteUsers(invitees); });
}); });
roomMembers_ = new QAction(tr("Members"), this);
connect(roomMembers_, &QAction::triggered, this, []() {
MainWindow::instance()->openMemberListDialog();
});
leaveRoom_ = new QAction(tr("Leave room"), this); leaveRoom_ = new QAction(tr("Leave room"), this);
connect(leaveRoom_, &QAction::triggered, this, []() { connect(leaveRoom_, &QAction::triggered, this, []() {
MainWindow::instance()->openLeaveRoomDialog(); MainWindow::instance()->openLeaveRoomDialog();
@ -101,6 +106,7 @@ TopRoomBar::TopRoomBar(QWidget *parent)
}); });
menu_->addAction(inviteUsers_); menu_->addAction(inviteUsers_);
menu_->addAction(roomMembers_);
menu_->addAction(leaveRoom_); menu_->addAction(leaveRoom_);
menu_->addAction(roomSettings_); menu_->addAction(roomSettings_);

145
src/dialogs/MemberList.cpp Normal file
View file

@ -0,0 +1,145 @@
#include <QListWidgetItem>
#include <QPainter>
#include <QStyleOption>
#include <QVBoxLayout>
#include "Config.h"
#include "FlatButton.h"
#include "Utils.h"
#include "Avatar.h"
#include "Cache.h"
#include "dialogs/MemberList.hpp"
using namespace dialogs;
MemberItem::MemberItem(const RoomMember &member, QWidget *parent)
: QWidget(parent)
{
topLayout_ = new QHBoxLayout(this);
topLayout_->setMargin(0);
textLayout_ = new QVBoxLayout;
textLayout_->setMargin(0);
textLayout_->setSpacing(0);
avatar_ = new Avatar(this);
avatar_->setSize(44);
avatar_->setLetter(utils::firstChar(member.display_name));
if (!member.avatar.isNull())
avatar_->setImage(member.avatar);
QFont nameFont, idFont;
nameFont.setWeight(65);
nameFont.setPixelSize(conf::receipts::font + 1);
idFont.setWeight(50);
idFont.setPixelSize(conf::receipts::font);
userName_ = new QLabel(member.display_name, this);
userName_->setFont(nameFont);
userId_ = new QLabel(member.user_id, this);
userId_->setFont(idFont);
textLayout_->addWidget(userName_);
textLayout_->addWidget(userId_);
topLayout_->addWidget(avatar_);
topLayout_->addLayout(textLayout_, 1);
}
MemberList::MemberList(const QString &room_id, QSharedPointer<Cache> cache, QWidget *parent)
: QFrame(parent)
, room_id_{room_id}
, cache_{cache}
{
setMaximumSize(420, 380);
setAttribute(Qt::WA_DeleteOnClose, true);
auto layout = new QVBoxLayout(this);
layout->setSpacing(30);
layout->setMargin(20);
list_ = new QListWidget;
list_->setFrameStyle(QFrame::NoFrame);
list_->setSelectionMode(QAbstractItemView::NoSelection);
list_->setAttribute(Qt::WA_MacShowFocusRect, 0);
list_->setSpacing(5);
QFont font;
font.setPixelSize(conf::headerFontSize);
topLabel_ = new QLabel(tr("Room members"), this);
topLabel_->setAlignment(Qt::AlignCenter);
topLabel_->setFont(font);
layout->addWidget(topLabel_);
layout->addWidget(list_);
list_->clear();
// Add button at the bottom.
moreBtn_ = new FlatButton(tr("SHOW MORE"), this);
auto item = new QListWidgetItem;
item->setSizeHint(moreBtn_->minimumSizeHint());
item->setFlags(Qt::NoItemFlags);
item->setTextAlignment(Qt::AlignCenter);
list_->insertItem(0, item);
list_->setItemWidget(item, moreBtn_);
connect(moreBtn_, &FlatButton::clicked, this, [this]() {
const size_t numMembers = list_->count() - 1;
if (numMembers > 0)
addUsers(cache_->getMembers(room_id_.toStdString(), numMembers));
});
try {
addUsers(cache_->getMembers(room_id_.toStdString()));
} catch (const lmdb::error &e) {
qCritical() << e.what();
}
}
void
MemberList::moveButtonToBottom()
{
auto item = new QListWidgetItem(list_);
item->setSizeHint(moreBtn_->minimumSizeHint());
item->setFlags(Qt::NoItemFlags);
item->setTextAlignment(Qt::AlignCenter);
list_->setItemWidget(item, moreBtn_);
list_->addItem(item);
}
void
MemberList::addUsers(const std::vector<RoomMember> &members)
{
if (members.size() == 0) {
moreBtn_->hide();
} else {
moreBtn_->show();
}
for (const auto &member : members) {
auto user = new MemberItem(member, this);
auto item = new QListWidgetItem;
item->setSizeHint(user->minimumSizeHint());
item->setFlags(Qt::NoItemFlags);
item->setTextAlignment(Qt::AlignCenter);
list_->insertItem(list_->count() - 1, item);
list_->setItemWidget(item, user);
}
}
void
MemberList::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

View file

@ -49,18 +49,20 @@ RoomSettings::RoomSettings(const QString &room_id, QSharedPointer<Cache> cache,
auto notifOptionLayout_ = new QHBoxLayout; auto notifOptionLayout_ = new QHBoxLayout;
notifOptionLayout_->setMargin(5); notifOptionLayout_->setMargin(5);
auto themeLabel_ = new QLabel(tr("Notifications"), this); auto notifLabel = new QLabel(tr("Notifications"), this);
auto notifCombo = new QComboBox(this); auto notifCombo = new QComboBox(this);
notifCombo->addItem("Nothing"); notifCombo->setDisabled(true);
notifCombo->addItem("Mentions only"); notifCombo->addItem(tr("Muted"));
notifCombo->addItem("All messages"); notifCombo->addItem(tr("Mentions only"));
themeLabel_->setStyleSheet("font-size: 15px;"); notifCombo->addItem(tr("All messages"));
notifLabel->setStyleSheet("font-size: 15px;");
notifOptionLayout_->addWidget(themeLabel_); notifOptionLayout_->addWidget(notifLabel);
notifOptionLayout_->addWidget(notifCombo, 0, Qt::AlignBottom | Qt::AlignRight); notifOptionLayout_->addWidget(notifCombo, 0, Qt::AlignBottom | Qt::AlignRight);
layout->addWidget(new TopSection(info_, avatarImg_, this)); layout->addWidget(new TopSection(info_, avatarImg_, this));
layout->addLayout(notifOptionLayout_); layout->addLayout(notifOptionLayout_);
layout->addLayout(notifOptionLayout_);
layout->addLayout(btnLayout); layout->addLayout(btnLayout);
connect(cancelBtn_, &FlatButton::clicked, this, &RoomSettings::closing); connect(cancelBtn_, &FlatButton::clicked, this, &RoomSettings::closing);

View file

@ -23,7 +23,7 @@
OverlayModal::OverlayModal(QWidget *parent, QWidget *content) OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
: OverlayWidget(parent) : OverlayWidget(parent)
, content_{content} , content_{content}
, color_{QColor(55, 55, 55)} , color_{QColor(30, 30, 30, 170)}
{ {
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
layout->addWidget(content); layout->addWidget(content);