From 77a0c574bfc962b6c37426fb16a70ca16c08a3f5 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Sat, 29 May 2021 21:09:21 -0400 Subject: QML the room member list --- src/MemberList.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/MemberList.cpp (limited to 'src/MemberList.cpp') diff --git a/src/MemberList.cpp b/src/MemberList.cpp new file mode 100644 index 00000000..62488277 --- /dev/null +++ b/src/MemberList.cpp @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MemberList.h" + +#include "Cache.h" +#include "ChatPage.h" +#include "Config.h" +#include "Logging.h" +#include "Utils.h" +#include "timeline/TimelineViewManager.h" +#include "ui/Avatar.h" + +MemberList::MemberList(const QString &room_id, QWidget *parent) + : QAbstractListModel{parent} + , room_id_{room_id} +{ + try { + info_ = cache::singleRoomInfo(room_id_.toStdString()); + } catch (const lmdb::error &) { + nhlog::db()->warn("failed to retrieve room info from cache: {}", + room_id_.toStdString()); + } + + try { + addUsers(cache::getMembers(room_id_.toStdString())); + } catch (const lmdb::error &e) { + nhlog::db()->critical("Failed to retrieve members from cache: {}", e.what()); + } +} + +void +MemberList::addUsers(const std::vector &members) +{ + beginInsertRows(QModelIndex{}, m_memberList.count(), m_memberList.count() + members.size() - 1); + + for (const auto &member : members) + m_memberList.push_back( + {member, + ChatPage::instance()->timelineManager()->rooms()->currentRoom()->avatarUrl( + member.user_id)}); + + endInsertRows(); +} + +QHash +MemberList::roleNames() const +{ + return {{Mxid, "mxid"}, {DisplayName, "displayName"}, {AvatarUrl, "avatarUrl"}}; +} + +QVariant +MemberList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= (int)m_memberList.size() || index.row() < 0) + return {}; + + switch (role) { + case Mxid: + return m_memberList[index.row()].first.user_id; + case DisplayName: + return m_memberList[index.row()].first.display_name; + case AvatarUrl: + return m_memberList[index.row()].second; + default: + return {}; + } +} + +bool MemberList::canFetchMore(const QModelIndex &) const +{ + const size_t numMembers = rowCount(); + return (numMembers > 1 && numMembers < info_.member_count); +} + +void +MemberList::fetchMore(const QModelIndex &) +{ + addUsers(cache::getMembers(room_id_.toStdString(), rowCount())); +} -- cgit 1.5.1 From e1acf5d324615e8c61c469883a6a42933c8f76bc Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Thu, 10 Jun 2021 20:13:12 -0400 Subject: make lint --- CMakeLists.txt | 2 + resources/qml/InviteDialog.qml | 78 +++++++++++++++++++++++------------- resources/qml/RoomMembers.qml | 9 +++++ resources/qml/Root.qml | 38 ++++++++++++++++++ resources/qml/TimelineView.qml | 1 - resources/qml/TopBar.qml | 14 +------ resources/qml/types/Invitee.qml | 5 --- resources/res.qrc | 1 - src/ChatPage.cpp | 49 +++++++++++----------- src/InviteesModel.cpp | 77 +++++++++++++++++++++++++++++++++++ src/InviteesModel.h | 56 ++++++++++++++++++++++++++ src/MemberList.cpp | 10 +++-- src/timeline/TimelineModel.cpp | 10 +++++ src/timeline/TimelineModel.h | 3 ++ src/timeline/TimelineViewManager.cpp | 70 +++++++------------------------- 15 files changed, 290 insertions(+), 133 deletions(-) delete mode 100644 resources/qml/types/Invitee.qml create mode 100644 src/InviteesModel.cpp create mode 100644 src/InviteesModel.h (limited to 'src/MemberList.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 56592950..f77d9978 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,6 +344,7 @@ set(SRC_FILES src/CompletionProxyModel.cpp src/DeviceVerificationFlow.cpp src/EventAccessors.cpp + src/InviteesModel.cpp src/Logging.cpp src/LoginPage.cpp src/MainWindow.cpp @@ -550,6 +551,7 @@ qt5_wrap_cpp(MOC_HEADERS src/Clipboard.h src/CompletionProxyModel.h src/DeviceVerificationFlow.h + src/InviteesModel.h src/LoginPage.h src/MainWindow.h src/MemberList.h diff --git a/resources/qml/InviteDialog.qml b/resources/qml/InviteDialog.qml index 5d3a8f1e..d5cc4c6d 100644 --- a/resources/qml/InviteDialog.qml +++ b/resources/qml/InviteDialog.qml @@ -2,50 +2,28 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import im.nheko 1.0 -import "./types" ApplicationWindow { id: inviteDialogRoot property string roomId property string roomName - property list invitees + property InviteesModel invitees function addInvite() { if (inviteeEntry.text.match("@.+?:.{3,}")) { - invitees.push(inviteeComponent.createObject( - inviteDialogRoot, { - "invitee": inviteeEntry.text - })); + invitees.addUser(inviteeEntry.text); inviteeEntry.clear(); } } - function accept() { - if (inviteeEntry.text !== "") - addInvite(); - - var inviteeStringList = ["temp"]; // the "temp" element exists to declare this as a string array - for (var i = 0; i < invitees.length; ++i) - inviteeStringList.push(invitees[i].invitee); - inviteeStringList.shift(); // remove the first item - - TimelineManager.inviteUsers(inviteDialogRoot.roomId, inviteeStringList); - } - title: qsTr("Invite users to ") + roomName x: MainWindow.x + (MainWindow.width / 2) - (width / 2) y: MainWindow.y + (MainWindow.height / 2) - (height / 2) height: 380 width: 340 - Component { - id: inviteeComponent - - Invitee {} - } - // TODO: make this work in the TextField Shortcut { sequence: "Ctrl+Enter" @@ -74,7 +52,7 @@ ApplicationWindow { } Button { - text: qsTr("Invite") + text: qsTr("Add") onClicked: if (inviteeEntry.text !== "") addInvite() } } @@ -85,9 +63,53 @@ ApplicationWindow { Layout.fillWidth: true Layout.fillHeight: true model: invitees - delegate: Label { - text: model.invitee + + delegate: RowLayout { + spacing: 10 + + Avatar { + width: avatarSize + height: avatarSize + userid: model.mxid + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + displayName: model.displayName + onClicked: TimelineManager.timeline.openUserProfile(model.mxid) + } + + ColumnLayout { + spacing: 5 + + Label { + text: model.displayName + color: TimelineManager.userColor(model ? model.mxid : "", colors.window) + font.pointSize: 12 + } + + Label { + text: model.mxid + color: colors.buttonText + font.pointSize: 10 + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + } } +// delegate: RowLayout { +// spacing: 10 + +// Avatar { +// url: model.avatarUrl +// width: 20 +// height: width +// } + +// Label { +// text: model.displayName + " (" + model.mxid + ")" +// } +// } } } @@ -98,7 +120,7 @@ ApplicationWindow { text: qsTr("Invite") DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole onClicked: { - inviteDialogRoot.accept(); + invitees.accept(); inviteDialogRoot.close(); } } diff --git a/resources/qml/RoomMembers.qml b/resources/qml/RoomMembers.qml index 4406c1b0..d31fe319 100644 --- a/resources/qml/RoomMembers.qml +++ b/resources/qml/RoomMembers.qml @@ -44,6 +44,15 @@ ApplicationWindow { Layout.alignment: Qt.AlignHCenter } + ImageButton { + Layout.alignment: Qt.AlignHCenter + image: ":/icons/icons/ui/add-square-button.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Invite more people") + onClicked: TimelineManager.timeline.openInviteUsersDialog() + } + ScrollView { clip: false palette: colors diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 5316e20d..ecd0bdb7 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -89,6 +89,12 @@ Page { } } + Component { + id: inviteDialog + + InviteDialog { + } + } Connections { target: TimelineManager @@ -116,6 +122,38 @@ Page { } } + Connections { + target: TimelineManager.timeline + onOpenRoomMembersDialog: { + var membersDialog = roomMembersComponent.createObject(timelineRoot, { + "members": members, + "roomName": TimelineManager.timeline.roomName + }); + membersDialog.show(); + } + } + + Connections { + target: TimelineManager.timeline + onOpenRoomSettingsDialog: { + var roomSettings = roomSettingsComponent.createObject(timelineRoot, { + "roomSettings": settings + }); + roomSettings.show(); + } + } + + Connections { + target: TimelineManager.timeline + onOpenInviteUsersDialog: { + var dialog = inviteDialog.createObject(timelineRoot, { + "roomId": TimelineManager.timeline.roomId, + "roomName": TimelineManager.timeline.roomName + }); + dialog.show(); + } + } + ChatPage { anchors.fill: parent } diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 148a5817..d515b9b4 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -157,7 +157,6 @@ Item { Layout.alignment: Qt.AlignHCenter enabled: false } - MatrixText { text: parent.roomName font.pixelSize: 24 diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index 72dbe604..6cf747c5 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -21,12 +21,6 @@ Rectangle { z: 3 color: Nheko.colors.window - Component { - id: inviteDialog - - InviteDialog {} - } - TapHandler { onSingleTapped: { if (room) @@ -117,13 +111,7 @@ Rectangle { Platform.MenuItem { visible: room ? room.permissions.canInvite() : false text: qsTr("Invite users") - onTriggered: { - var dialog = inviteDialog.createObject(topBar, { - "roomId": room.roomId, - "roomName": room.roomName - }); - dialog.show(); - } + onTriggered: TimelineManager.timeline.openInviteUsers() } Platform.MenuItem { diff --git a/resources/qml/types/Invitee.qml b/resources/qml/types/Invitee.qml deleted file mode 100644 index fbc0b781..00000000 --- a/resources/qml/types/Invitee.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQuick 2.12 - -Item { - property string invitee -} diff --git a/resources/res.qrc b/resources/res.qrc index ad7b6665..f8c040e4 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -176,7 +176,6 @@ qml/components/FlatButton.qml qml/RoomMembers.qml qml/InviteDialog.qml - qml/types/Invitee.qml media/ring.ogg diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index f6ea4539..8b4cfeef 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -116,32 +116,31 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) connect(this, &ChatPage::loggedOut, this, &ChatPage::logout); - connect(view_manager_, &TimelineViewManager::inviteUsers, this, [this](QStringList users) { - const auto room_id = currentRoom().toStdString(); - - for (int ii = 0; ii < users.size(); ++ii) { - QTimer::singleShot(ii * 500, this, [this, room_id, ii, users]() { - const auto user = users.at(ii); - - http::client()->invite_user( - room_id, - user.toStdString(), - [this, user](const mtx::responses::RoomInvite &, - mtx::http::RequestErr err) { - if (err) { - emit showNotification( - tr("Failed to invite user: %1").arg(user)); - return; - } + // TODO: once this signal is moved, reenable this +// connect(view_manager_, &TimelineViewManager::inviteUsers, this, [this](QStringList users) { +// const auto room_id = currentRoom().toStdString(); + +// for (int ii = 0; ii < users.size(); ++ii) { +// QTimer::singleShot(ii * 500, this, [this, room_id, ii, users]() { +// const auto user = users.at(ii); + +// http::client()->invite_user( +// room_id, +// user.toStdString(), +// [this, user](const mtx::responses::RoomInvite &, +// mtx::http::RequestErr err) { +// if (err) { +// emit showNotification( +// tr("Failed to invite user: %1").arg(user)); +// return; +// } + +// emit showNotification(tr("Invited user: %1").arg(user)); +// }); +// }); +// } +// }); - emit showNotification(tr("Invited user: %1").arg(user)); - }); - }); - } - }); - - connect( - view_manager_, &TimelineViewManager::showRoomList, splitter, &Splitter::showFullRoomList); connect( view_manager_, &TimelineViewManager::inviteUsers, diff --git a/src/InviteesModel.cpp b/src/InviteesModel.cpp new file mode 100644 index 00000000..849c5281 --- /dev/null +++ b/src/InviteesModel.cpp @@ -0,0 +1,77 @@ +#include "InviteesModel.h" + +#include "Cache.h" +#include "Logging.h" +#include "MatrixClient.h" +#include "mtx/responses/profile.hpp" + +InviteesModel::InviteesModel(QObject *parent) + : QAbstractListModel{parent} +{} + +void +InviteesModel::addUser(QString mxid) +{ + beginInsertRows(QModelIndex(), invitees_.count(), invitees_.count()); + + auto invitee = new Invitee{mxid, this}; + connect(invitee, &Invitee::userInfoLoaded, this, [this]() { + emit dataChanged(QModelIndex{}, QModelIndex{}); + }); + + invitees_.push_back(invitee); + + endInsertRows(); +} + +QHash +InviteesModel::roleNames() const +{ + return {{Mxid, "mxid"}, {DisplayName, "displayName"}, {AvatarUrl, "avatarUrl"}}; +} + +QVariant +InviteesModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= (int)invitees_.size() || index.row() < 0) + return {}; + + switch (role) { + case Mxid: + return invitees_[index.row()]->mxid_; + case DisplayName: + return invitees_[index.row()]->displayName_; + case AvatarUrl: + return invitees_[index.row()]->avatarUrl_; + default: + return {}; + } +} + +QStringList +InviteesModel::mxids() +{ + QStringList mxidList; + for (int i = 0; i < invitees_.length(); ++i) + mxidList.push_back(invitees_[i]->mxid_); + return mxidList; +} + +Invitee::Invitee(const QString &mxid, QObject *parent) + : QObject{parent} + , mxid_{mxid} +{ + http::client()->get_profile( + mxid_.toStdString(), + [this](const mtx::responses::Profile &res, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to retrieve own profile info"); + return; + } + + displayName_ = QString::fromStdString(res.display_name); + avatarUrl_ = QString::fromStdString(res.avatar_url); + + emit userInfoLoaded(); + }); +} diff --git a/src/InviteesModel.h b/src/InviteesModel.h new file mode 100644 index 00000000..4bcc4e9d --- /dev/null +++ b/src/InviteesModel.h @@ -0,0 +1,56 @@ +#ifndef INVITEESMODEL_H +#define INVITEESMODEL_H + +#include +#include + +class Invitee : public QObject +{ + Q_OBJECT + +public: + Invitee(const QString &mxid, QObject *parent = nullptr); + +signals: + void userInfoLoaded(); + +private: + const QString mxid_; + QString displayName_; + QString avatarUrl_; + + friend class InviteesModel; +}; + +class InviteesModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum Roles + { + Mxid, + DisplayName, + AvatarUrl, + }; + + InviteesModel(QObject *parent = nullptr); + + Q_INVOKABLE void addUser(QString mxid); + + QHash roleNames() const override; + int rowCount(const QModelIndex & = QModelIndex()) const override + { + return (int)invitees_.size(); + } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QStringList mxids(); + +signals: + void accept(); + +private: + QVector invitees_; +}; + +#endif // INVITEESMODEL_H diff --git a/src/MemberList.cpp b/src/MemberList.cpp index 62488277..2a9c3fbc 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -43,7 +43,8 @@ MemberList::MemberList(const QString &room_id, QWidget *parent) void MemberList::addUsers(const std::vector &members) { - beginInsertRows(QModelIndex{}, m_memberList.count(), m_memberList.count() + members.size() - 1); + beginInsertRows( + QModelIndex{}, m_memberList.count(), m_memberList.count() + members.size() - 1); for (const auto &member : members) m_memberList.push_back( @@ -78,10 +79,11 @@ MemberList::data(const QModelIndex &index, int role) const } } -bool MemberList::canFetchMore(const QModelIndex &) const +bool +MemberList::canFetchMore(const QModelIndex &) const { - const size_t numMembers = rowCount(); - return (numMembers > 1 && numMembers < info_.member_count); + const size_t numMembers = rowCount(); + return (numMembers > 1 && numMembers < info_.member_count); } void diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 48d69493..2127801c 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -1076,6 +1076,16 @@ TimelineModel::openRoomSettings(QString room_id) openRoomSettingsDialog(settings); } +void +TimelineModel::openInviteUsers(QString room_id) +{ + InviteesModel *model = new InviteesModel{this}; + connect(model, &InviteesModel::accept, this, [this, model, room_id]() { + manager_->inviteUsers(room_id, model->mxids()); + }); + openInviteUsersDialog(model); +} + void TimelineModel::replyAction(QString id) { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 5730fbab..e5189e61 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -17,6 +17,7 @@ #include "CacheStructs.h" #include "EventStore.h" #include "InputBar.h" +#include "InviteesModel.h" #include "MemberList.h" #include "Permissions.h" #include "ui/RoomSettings.h" @@ -239,6 +240,7 @@ public: Q_INVOKABLE void openUserProfile(QString userid); Q_INVOKABLE void openRoomMembers(); Q_INVOKABLE void openRoomSettings(QString room_id = QString()); + Q_INVOKABLE void openInviteUsers(QString room_id = QString()); Q_INVOKABLE void editAction(QString id); Q_INVOKABLE void replyAction(QString id); Q_INVOKABLE void readReceiptsAction(QString id) const; @@ -357,6 +359,7 @@ signals: void openRoomMembersDialog(MemberList *members); void openRoomSettingsDialog(RoomSettings *settings); + void openInviteUsersDialog(InviteesModel *invitees); void newMessageToSend(mtx::events::collections::TimelineEvents event); void addPendingMessageToStore(mtx::events::collections::TimelineEvents event); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 43b9a646..08b88efd 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -20,6 +20,7 @@ #include "DeviceVerificationFlow.h" #include "EventAccessors.h" #include "ImagePackModel.h" +#include "InviteesModel.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" @@ -184,6 +185,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par "Room Settings needs to be instantiated on the C++ side"); qmlRegisterUncreatableType( "im.nheko", 1, 0, "Room", "Room needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType( + "im.nheko", + 1, + 0, + "InviteesModel", + "InviteesModel needs to be instantiated on the C++ side"); static auto self = this; qmlRegisterSingletonType( @@ -423,62 +430,13 @@ TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img) }); } -void -TimelineViewManager::openInviteUsersDialog() -{ - MainWindow::instance()->openInviteUsersDialog( - [this](const QStringList &invitees) { emit inviteUsers(invitees); }); -} - -void -TimelineViewManager::openLink(QString link) const -{ - QUrl url(link); - if (url.scheme() == "https" && url.host() == "matrix.to") { - // handle matrix.to links internally - QString p = url.fragment(QUrl::FullyEncoded); - if (p.startsWith("/")) - p.remove(0, 1); - - auto temp = p.split("?"); - QString query; - if (temp.size() >= 2) - query = QUrl::fromPercentEncoding(temp.takeAt(1).toUtf8()); - - temp = temp.first().split("/"); - auto identifier = QUrl::fromPercentEncoding(temp.takeFirst().toUtf8()); - QString eventId = QUrl::fromPercentEncoding(temp.join('/').toUtf8()); - if (!identifier.isEmpty()) { - if (identifier.startsWith("@")) { - QByteArray uri = - "matrix:u/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } else if (identifier.startsWith("#")) { - QByteArray uri = - "matrix:r/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!eventId.isEmpty()) - uri.append("/e/" + - QUrl::toPercentEncoding(eventId.remove(0, 1))); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } else if (identifier.startsWith("!")) { - QByteArray uri = "matrix:roomid/" + - QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!eventId.isEmpty()) - uri.append("/e/" + - QUrl::toPercentEncoding(eventId.remove(0, 1))); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } - } - } else { - QDesktopServices::openUrl(url); - } -} +//void +//TimelineViewManager::openInviteUsersDialog() +//{ + // TODO: move this somewhere where it will actually work (probably Rooms) +// MainWindow::instance()->openInviteUsersDialog( +// [this](const QStringList &invitees) { emit inviteUsers(invitees); }); +//} void TimelineViewManager::openLeaveRoomDialog(QString roomid) const -- cgit 1.5.1 From a76fc7d20058fa10e1345e0de0a1431a7161cd57 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Fri, 11 Jun 2021 18:53:32 -0400 Subject: Add a fancy loading spinner to the member list --- resources/qml/RoomMembers.qml | 7 +++++++ src/MemberList.cpp | 15 ++++++++++++--- src/MemberList.h | 4 ++++ 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'src/MemberList.cpp') diff --git a/resources/qml/RoomMembers.qml b/resources/qml/RoomMembers.qml index d31fe319..8060a6cc 100644 --- a/resources/qml/RoomMembers.qml +++ b/resources/qml/RoomMembers.qml @@ -109,6 +109,13 @@ ApplicationWindow { } } } + + footer: BusyIndicator { + // This is not a wonderful solution, but it is the best way to calculate whether + // all users are loaded while keeping canFetchMore() const + running: members.numUsersLoaded < members.memberCount + anchors.centerIn: parent + } } } } diff --git a/src/MemberList.cpp b/src/MemberList.cpp index 2a9c3fbc..da4412d2 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -34,7 +34,10 @@ MemberList::MemberList(const QString &room_id, QWidget *parent) } try { - addUsers(cache::getMembers(room_id_.toStdString())); + auto members = cache::getMembers(room_id_.toStdString()); + addUsers(members); + numUsersLoaded_ = members.size(); + emit numUsersLoadedChanged(); } catch (const lmdb::error &e) { nhlog::db()->critical("Failed to retrieve members from cache: {}", e.what()); } @@ -83,11 +86,17 @@ bool MemberList::canFetchMore(const QModelIndex &) const { const size_t numMembers = rowCount(); - return (numMembers > 1 && numMembers < info_.member_count); + if (numMembers > 1 && numMembers < info_.member_count) + return true; + else + return false; } void MemberList::fetchMore(const QModelIndex &) { - addUsers(cache::getMembers(room_id_.toStdString(), rowCount())); + auto members = cache::getMembers(room_id_.toStdString(), rowCount()); + addUsers(members); + numUsersLoaded_ = members.size(); + emit numUsersLoadedChanged(); } diff --git a/src/MemberList.h b/src/MemberList.h index dbe69f4b..afc1a6e5 100644 --- a/src/MemberList.h +++ b/src/MemberList.h @@ -15,6 +15,7 @@ class MemberList : public QAbstractListModel Q_PROPERTY(size_t memberCount READ memberCount NOTIFY memberCountChanged) Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged) Q_PROPERTY(QString roomId READ roomId NOTIFY roomIdChanged) + Q_PROPERTY(int numUsersLoaded READ numUsersLoaded NOTIFY numUsersLoadedChanged) public: enum Roles @@ -37,12 +38,14 @@ public: size_t memberCount() const { return info_.member_count; } QString avatarUrl() const { return QString::fromStdString(info_.avatar_url); } QString roomId() const { return room_id_; } + int numUsersLoaded() const { return numUsersLoaded_; } signals: void roomNameChanged(); void memberCountChanged(); void avatarUrlChanged(); void roomIdChanged(); + void numUsersLoadedChanged(); public slots: void addUsers(const std::vector &users); @@ -55,4 +58,5 @@ private: QVector> m_memberList; QString room_id_; RoomInfo info_; + int numUsersLoaded_; }; -- cgit 1.5.1 From db8af24bea5b46b76c0afd90813a4a29e13eea28 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Sat, 12 Jun 2021 22:00:14 -0400 Subject: Don't emit signal in constructor --- src/MemberList.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/MemberList.cpp') diff --git a/src/MemberList.cpp b/src/MemberList.cpp index da4412d2..7f4dfa99 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -37,7 +37,6 @@ MemberList::MemberList(const QString &room_id, QWidget *parent) auto members = cache::getMembers(room_id_.toStdString()); addUsers(members); numUsersLoaded_ = members.size(); - emit numUsersLoadedChanged(); } catch (const lmdb::error &e) { nhlog::db()->critical("Failed to retrieve members from cache: {}", e.what()); } -- cgit 1.5.1 From f30c3db86058f2700a1e2331bb1167d2ebf88f4d Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Sat, 17 Jul 2021 18:24:04 -0400 Subject: Fix loaded member count --- src/MemberList.cpp | 2 +- src/MemberList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/MemberList.cpp') diff --git a/src/MemberList.cpp b/src/MemberList.cpp index 7f4dfa99..b2ed82bd 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -96,6 +96,6 @@ MemberList::fetchMore(const QModelIndex &) { auto members = cache::getMembers(room_id_.toStdString(), rowCount()); addUsers(members); - numUsersLoaded_ = members.size(); + numUsersLoaded_ += members.size(); emit numUsersLoadedChanged(); } diff --git a/src/MemberList.h b/src/MemberList.h index 80ab834c..aa240b7a 100644 --- a/src/MemberList.h +++ b/src/MemberList.h @@ -58,5 +58,5 @@ private: QVector> m_memberList; QString room_id_; RoomInfo info_; - int numUsersLoaded_; + int numUsersLoaded_{0}; }; -- cgit 1.5.1 From 10c6f2b43fa88830e4a693e8a71734ab90c053c2 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Mon, 19 Jul 2021 12:33:54 -0400 Subject: Use Nico's favored formatting (*shrugs*) --- src/MemberList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/MemberList.cpp') diff --git a/src/MemberList.cpp b/src/MemberList.cpp index b2ed82bd..dd5997f5 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -60,7 +60,7 @@ MemberList::addUsers(const std::vector &members) QHash MemberList::roleNames() const { - return {{Mxid, "mxid"}, {DisplayName, "displayName"}, {AvatarUrl, "avatarUrl"}}; + return {{Mxid, "mxid"}, {DisplayName, "displayName"}, {AvatarUrl, "avatarUrl"},}; } QVariant -- cgit 1.5.1 From 48669302ece255010f31150543d8e0ef4830fb74 Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Mon, 19 Jul 2021 14:31:08 -0400 Subject: make lint --- resources/qml/InviteDialog.qml | 13 ++++++++----- resources/qml/RoomMembers.qml | 8 +++++++- resources/qml/Root.qml | 3 +++ src/MemberList.cpp | 6 +++++- 4 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src/MemberList.cpp') diff --git a/resources/qml/InviteDialog.qml b/resources/qml/InviteDialog.qml index 94a95861..b1b1bb39 100644 --- a/resources/qml/InviteDialog.qml +++ b/resources/qml/InviteDialog.qml @@ -24,6 +24,7 @@ ApplicationWindow { function cleanUpAndClose() { if (inviteeEntry.text.match("@.+?:.{3,}")) addInvite(); + invitees.accept(); close(); } @@ -64,15 +65,17 @@ ApplicationWindow { placeholderText: qsTr("@joe:matrix.org", "Example user id. The name 'joe' can be localized however you want.") Layout.fillWidth: true onAccepted: { - if (text !== "") { + if (text !== "") addInvite(); - } + } Component.onCompleted: forceActiveFocus() - Keys.onShortcutOverride: event.accepted = ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (event.modifiers & Qt.ControlModifier)) - Keys.onPressed: if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (event.modifiers === Qt.ControlModifier)) cleanUpAndClose() - + Keys.onPressed: { + if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && (event.modifiers === Qt.ControlModifier)) { + cleanUpAndClose(); + } + } } Button { diff --git a/resources/qml/RoomMembers.qml b/resources/qml/RoomMembers.qml index 0d957165..57353132 100644 --- a/resources/qml/RoomMembers.qml +++ b/resources/qml/RoomMembers.qml @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +import "./ui" import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Window 2.12 import im.nheko 1.0 -import "./ui" ApplicationWindow { id: roomMembersRoot @@ -110,7 +110,9 @@ ApplicationWindow { Layout.fillHeight: true Layout.fillWidth: true } + } + } footer: Spinner { @@ -119,12 +121,16 @@ ApplicationWindow { height: visible ? undefined : 0 anchors.centerIn: parent } + } + } + } footer: DialogButtonBox { standardButtons: DialogButtonBox.Ok onAccepted: roomMembersRoot.close() } + } diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 31d00585..102d0411 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -52,6 +52,7 @@ Page { RoomMembers { } + } Component { @@ -77,11 +78,13 @@ Page { } } + Component { id: inviteDialog InviteDialog { } + } Shortcut { diff --git a/src/MemberList.cpp b/src/MemberList.cpp index dd5997f5..04377a0f 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -60,7 +60,11 @@ MemberList::addUsers(const std::vector &members) QHash MemberList::roleNames() const { - return {{Mxid, "mxid"}, {DisplayName, "displayName"}, {AvatarUrl, "avatarUrl"},}; + return { + {Mxid, "mxid"}, + {DisplayName, "displayName"}, + {AvatarUrl, "avatarUrl"}, + }; } QVariant -- cgit 1.5.1 From 21eb312f69111b8141e2ac9da5bb3871287045bd Mon Sep 17 00:00:00 2001 From: Loren Burkholder Date: Mon, 19 Jul 2021 14:49:57 -0400 Subject: Only run spinner while loading members --- resources/qml/RoomMembers.qml | 2 +- src/MemberList.cpp | 6 ++++++ src/MemberList.h | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/MemberList.cpp') diff --git a/resources/qml/RoomMembers.qml b/resources/qml/RoomMembers.qml index 57353132..b190be07 100644 --- a/resources/qml/RoomMembers.qml +++ b/resources/qml/RoomMembers.qml @@ -116,7 +116,7 @@ ApplicationWindow { } footer: Spinner { - visible: members.numUsersLoaded < members.memberCount + visible: members.numUsersLoaded < members.memberCount && members.loadingMoreMembers // use the default height if it's visible, otherwise no height at all height: visible ? undefined : 0 anchors.centerIn: parent diff --git a/src/MemberList.cpp b/src/MemberList.cpp index 04377a0f..415e3b57 100644 --- a/src/MemberList.cpp +++ b/src/MemberList.cpp @@ -98,8 +98,14 @@ MemberList::canFetchMore(const QModelIndex &) const void MemberList::fetchMore(const QModelIndex &) { + loadingMoreMembers_ = true; + emit loadingMoreMembersChanged(); + auto members = cache::getMembers(room_id_.toStdString(), rowCount()); addUsers(members); numUsersLoaded_ += members.size(); emit numUsersLoadedChanged(); + + loadingMoreMembers_ = false; + emit loadingMoreMembersChanged(); } diff --git a/src/MemberList.h b/src/MemberList.h index cc3b75f7..070666a2 100644 --- a/src/MemberList.h +++ b/src/MemberList.h @@ -16,6 +16,7 @@ class MemberList : public QAbstractListModel Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged) Q_PROPERTY(QString roomId READ roomId NOTIFY roomIdChanged) Q_PROPERTY(int numUsersLoaded READ numUsersLoaded NOTIFY numUsersLoadedChanged) + Q_PROPERTY(bool loadingMoreMembers READ loadingMoreMembers NOTIFY loadingMoreMembersChanged) public: enum Roles @@ -39,6 +40,7 @@ public: QString avatarUrl() const { return QString::fromStdString(info_.avatar_url); } QString roomId() const { return room_id_; } int numUsersLoaded() const { return numUsersLoaded_; } + bool loadingMoreMembers() const { return loadingMoreMembers_; } signals: void roomNameChanged(); @@ -46,6 +48,7 @@ signals: void avatarUrlChanged(); void roomIdChanged(); void numUsersLoadedChanged(); + void loadingMoreMembersChanged(); public slots: void addUsers(const std::vector &users); @@ -59,4 +62,5 @@ private: QString room_id_; RoomInfo info_; int numUsersLoaded_{0}; + bool loadingMoreMembers_{false}; }; -- cgit 1.5.1