summary refs log tree commit diff
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2018-05-01 19:35:28 +0300
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2018-05-01 19:35:28 +0300
commit763330fd3c259b7a877eb05944783e92c0afcb80 (patch)
treecf6810cba9aded346ecf8c3dbede7ed0e7d8d68f
parentAdd prototype room settings menu (diff)
downloadnheko-763330fd3c259b7a877eb05944783e92c0afcb80.tar.xz
Add member list
Diffstat (limited to '')
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/Cache.h13
-rw-r--r--include/MainWindow.h6
-rw-r--r--include/TopRoomBar.h1
-rw-r--r--include/dialogs/MemberList.hpp57
-rw-r--r--resources/styles/nheko-dark.qss1
-rw-r--r--resources/styles/nheko.qss1
-rw-r--r--src/Cache.cc42
-rw-r--r--src/MainWindow.cc22
-rw-r--r--src/TopRoomBar.cc6
-rw-r--r--src/dialogs/MemberList.cpp145
-rw-r--r--src/dialogs/RoomSettings.cpp18
-rw-r--r--src/ui/OverlayModal.cc2
13 files changed, 301 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e1d835f6..e85c586b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,6 +102,7 @@ set(SRC_FILES
     src/dialogs/PreviewUploadOverlay.cc
     src/dialogs/InviteUsers.cc
     src/dialogs/JoinRoom.cc
+    src/dialogs/MemberList.cpp
     src/dialogs/LeaveRoom.cc
     src/dialogs/Logout.cc
     src/dialogs/ReadReceipts.cc
@@ -219,6 +220,7 @@ qt5_wrap_cpp(MOC_HEADERS
     include/dialogs/PreviewUploadOverlay.h
     include/dialogs/InviteUsers.h
     include/dialogs/JoinRoom.h
+    include/dialogs/MemberList.hpp
     include/dialogs/LeaveRoom.h
     include/dialogs/Logout.h
     include/dialogs/ReadReceipts.h
diff --git a/include/Cache.h b/include/Cache.h
index db5dba00..e0b68549 100644
--- a/include/Cache.h
+++ b/include/Cache.h
@@ -24,6 +24,13 @@
 #include <lmdb++.h>
 #include <mtx/responses.hpp>
 
+struct RoomMember
+{
+        QString user_id;
+        QString display_name;
+        QImage avatar;
+};
+
 struct SearchResult
 {
         QString user_id;
@@ -32,6 +39,7 @@ struct SearchResult
 
 Q_DECLARE_METATYPE(SearchResult)
 Q_DECLARE_METATYPE(QVector<SearchResult>)
+Q_DECLARE_METATYPE(RoomMember);
 
 //! Used to uniquely identify a list of read receipts.
 struct ReadReceiptKey
@@ -164,6 +172,11 @@ public:
                                  lmdb::dbi &membersdb,
                                  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);
         bool isInitialized() const;
 
diff --git a/include/MainWindow.h b/include/MainWindow.h
index 08d7e53e..1ffbe850 100644
--- a/include/MainWindow.h
+++ b/include/MainWindow.h
@@ -49,6 +49,7 @@ class InviteUsers;
 class JoinRoom;
 class LeaveRoom;
 class Logout;
+class MemberList;
 class ReCaptcha;
 class RoomSettings;
 }
@@ -70,6 +71,7 @@ public:
         void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
         void openLogoutDialog(std::function<void()> callback);
         void openRoomSettings(const QString &room_id = "");
+        void openMemberListDialog(const QString &room_id = "");
 
 protected:
         void closeEvent(QCloseEvent *event);
@@ -153,4 +155,8 @@ private:
         QSharedPointer<OverlayModal> roomSettingsModal_;
         //! Room settings dialog.
         QSharedPointer<dialogs::RoomSettings> roomSettingsDialog_;
+        //! Member list modal.
+        QSharedPointer<OverlayModal> memberListModal_;
+        //! Member list dialog.
+        QSharedPointer<dialogs::MemberList> memberListDialog_;
 };
diff --git a/include/TopRoomBar.h b/include/TopRoomBar.h
index 37a0b61b..54b89a59 100644
--- a/include/TopRoomBar.h
+++ b/include/TopRoomBar.h
@@ -67,6 +67,7 @@ private:
 
         Menu *menu_;
         QAction *leaveRoom_;
+        QAction *roomMembers_;
         QAction *roomSettings_;
         QAction *inviteUsers_;
 
diff --git a/include/dialogs/MemberList.hpp b/include/dialogs/MemberList.hpp
new file mode 100644
index 00000000..09a56aab
--- /dev/null
+++ b/include/dialogs/MemberList.hpp
@@ -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
diff --git a/resources/styles/nheko-dark.qss b/resources/styles/nheko-dark.qss
index 89582348..e0a6fe20 100644
--- a/resources/styles/nheko-dark.qss
+++ b/resources/styles/nheko-dark.qss
@@ -140,6 +140,7 @@ dialogs--RoomSettings,
 dialogs--InviteUsers,
 dialogs--ReadReceipts,
 dialogs--JoinRoom,
+dialogs--MemberList,
 dialogs--PreviewUploadOverlay,
 dialogs--CreateRoom > QLineEdit,
 dialogs--InviteUsers > QLineEdit,
diff --git a/resources/styles/nheko.qss b/resources/styles/nheko.qss
index 6538a780..2a746e37 100644
--- a/resources/styles/nheko.qss
+++ b/resources/styles/nheko.qss
@@ -141,6 +141,7 @@ dialogs--CreateRoom,
 dialogs--RoomSettings,
 dialogs--InviteUsers,
 dialogs--ReadReceipts,
+dialogs--MemberList,
 dialogs--JoinRoom,
 dialogs--PreviewUploadOverlay,
 QListWidget {
diff --git a/src/Cache.cc b/src/Cache.cc
index 60181afc..92c86322 100644
--- a/src/Cache.cc
+++ b/src/Cache.cc
@@ -1045,6 +1045,48 @@ Cache::searchUsers(const std::string &room_id, const std::string &query, std::ui
         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::AvatarUrls;
 
diff --git a/src/MainWindow.cc b/src/MainWindow.cc
index 66f956a5..c2353a11 100644
--- a/src/MainWindow.cc
+++ b/src/MainWindow.cc
@@ -41,6 +41,7 @@
 #include "dialogs/JoinRoom.h"
 #include "dialogs/LeaveRoom.h"
 #include "dialogs/Logout.h"
+#include "dialogs/MemberList.hpp"
 #include "dialogs/RoomSettings.hpp"
 
 MainWindow *MainWindow::instance_ = nullptr;
@@ -268,8 +269,6 @@ MainWindow::openRoomSettings(const QString &room_id)
 {
         const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : "";
 
-        qDebug() << "room settings" << roomToSearch;
-
         roomSettingsDialog_ = QSharedPointer<dialogs::RoomSettings>(
           new dialogs::RoomSettings(roomToSearch, chat_page_->cache(), this));
 
@@ -279,12 +278,25 @@ MainWindow::openRoomSettings(const QString &room_id)
 
         roomSettingsModal_ =
           QSharedPointer<OverlayModal>(new OverlayModal(this, roomSettingsDialog_.data()));
-        roomSettingsModal_->setColor(QColor(30, 30, 30, 170));
 
         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
 MainWindow::openLeaveRoomDialog(const QString &room_id)
 {
         auto roomToLeave = room_id.isEmpty() ? chat_page_->currentRoom() : room_id;
@@ -325,6 +337,7 @@ MainWindow::showOverlayProgressBar()
                 progressModal_ =
                   QSharedPointer<OverlayModal>(new OverlayModal(this, spinner_.data()),
                                                [](OverlayModal *modal) { modal->deleteLater(); });
+                progressModal_->setColor(QColor(30, 30, 30));
                 progressModal_->setDismissible(false);
                 progressModal_->show();
         }
@@ -377,7 +390,6 @@ MainWindow::openJoinRoomDialog(std::function<void(const QString &room_id)> callb
         if (joinRoomModal_.isNull()) {
                 joinRoomModal_ = QSharedPointer<OverlayModal>(
                   new OverlayModal(MainWindow::instance(), joinRoomDialog_.data()));
-                joinRoomModal_->setColor(QColor(30, 30, 30, 170));
         }
 
         joinRoomModal_->show();
@@ -406,7 +418,6 @@ MainWindow::openCreateRoomDialog(
         if (createRoomModal_.isNull()) {
                 createRoomModal_ = QSharedPointer<OverlayModal>(
                   new OverlayModal(MainWindow::instance(), createRoomDialog_.data()));
-                createRoomModal_->setColor(QColor(30, 30, 30, 170));
         }
 
         createRoomModal_->show();
@@ -431,7 +442,6 @@ MainWindow::openLogoutDialog(std::function<void()> callback)
         if (logoutModal_.isNull()) {
                 logoutModal_ = QSharedPointer<OverlayModal>(
                   new OverlayModal(MainWindow::instance(), logoutDialog_.data()));
-                logoutModal_->setColor(QColor(30, 30, 30, 170));
         }
 
         logoutModal_->show();
diff --git a/src/TopRoomBar.cc b/src/TopRoomBar.cc
index beca1d51..7338cfb1 100644
--- a/src/TopRoomBar.cc
+++ b/src/TopRoomBar.cc
@@ -90,6 +90,11 @@ TopRoomBar::TopRoomBar(QWidget *parent)
                   [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);
         connect(leaveRoom_, &QAction::triggered, this, []() {
                 MainWindow::instance()->openLeaveRoomDialog();
@@ -101,6 +106,7 @@ TopRoomBar::TopRoomBar(QWidget *parent)
         });
 
         menu_->addAction(inviteUsers_);
+        menu_->addAction(roomMembers_);
         menu_->addAction(leaveRoom_);
         menu_->addAction(roomSettings_);
 
diff --git a/src/dialogs/MemberList.cpp b/src/dialogs/MemberList.cpp
new file mode 100644
index 00000000..26f526dd
--- /dev/null
+++ b/src/dialogs/MemberList.cpp
@@ -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);
+}
diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp
index 8fcbc82f..b2c87c94 100644
--- a/src/dialogs/RoomSettings.cpp
+++ b/src/dialogs/RoomSettings.cpp
@@ -49,18 +49,20 @@ RoomSettings::RoomSettings(const QString &room_id, QSharedPointer<Cache> cache,
 
         auto notifOptionLayout_ = new QHBoxLayout;
         notifOptionLayout_->setMargin(5);
-        auto themeLabel_ = new QLabel(tr("Notifications"), this);
-        auto notifCombo  = new QComboBox(this);
-        notifCombo->addItem("Nothing");
-        notifCombo->addItem("Mentions only");
-        notifCombo->addItem("All messages");
-        themeLabel_->setStyleSheet("font-size: 15px;");
-
-        notifOptionLayout_->addWidget(themeLabel_);
+        auto notifLabel = new QLabel(tr("Notifications"), this);
+        auto notifCombo = new QComboBox(this);
+        notifCombo->setDisabled(true);
+        notifCombo->addItem(tr("Muted"));
+        notifCombo->addItem(tr("Mentions only"));
+        notifCombo->addItem(tr("All messages"));
+        notifLabel->setStyleSheet("font-size: 15px;");
+
+        notifOptionLayout_->addWidget(notifLabel);
         notifOptionLayout_->addWidget(notifCombo, 0, Qt::AlignBottom | Qt::AlignRight);
 
         layout->addWidget(new TopSection(info_, avatarImg_, this));
         layout->addLayout(notifOptionLayout_);
+        layout->addLayout(notifOptionLayout_);
         layout->addLayout(btnLayout);
 
         connect(cancelBtn_, &FlatButton::clicked, this, &RoomSettings::closing);
diff --git a/src/ui/OverlayModal.cc b/src/ui/OverlayModal.cc
index 4b0747a1..6aa16b07 100644
--- a/src/ui/OverlayModal.cc
+++ b/src/ui/OverlayModal.cc
@@ -23,7 +23,7 @@
 OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
   : OverlayWidget(parent)
   , content_{content}
-  , color_{QColor(55, 55, 55)}
+  , color_{QColor(30, 30, 30, 170)}
 {
         auto layout = new QVBoxLayout();
         layout->addWidget(content);