mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 11:00:48 +03:00
Search room members (#1049)
This commit is contained in:
parent
c637989ac0
commit
6672e765d7
4 changed files with 155 additions and 12 deletions
|
@ -117,12 +117,12 @@ ColumnLayout {
|
|||
palette: Nheko.colors
|
||||
color: labelC.color
|
||||
opacity: labelC.text ? 0 : 1
|
||||
focus: true
|
||||
|
||||
onTextEdited: c.textEdited()
|
||||
onAccepted: c.accepted()
|
||||
onEditingFinished: c.editingFinished()
|
||||
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
|
|
|
@ -63,6 +63,37 @@ ApplicationWindow {
|
|||
onClicked: TimelineManager.openInviteUsers(members.roomId)
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: searchBar
|
||||
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Search...")
|
||||
onTextChanged: members.setFilterString(text)
|
||||
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Nheko.paddingMedium
|
||||
|
||||
Label {
|
||||
text: qsTr("Sort by: ")
|
||||
color: Nheko.colors.text
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
model: ListModel {
|
||||
ListElement { data: MemberList.Mxid; text: qsTr("User ID") }
|
||||
ListElement { data: MemberList.DisplayName; text: qsTr("Display name") }
|
||||
ListElement { data: MemberList.Powerlevel; text: qsTr("Power level") }
|
||||
}
|
||||
textRole: "text"
|
||||
valueRole: "data"
|
||||
onCurrentValueChanged: members.sortBy(currentValue)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
palette: Nheko.colors
|
||||
padding: Nheko.paddingMedium
|
||||
|
@ -172,14 +203,14 @@ ApplicationWindow {
|
|||
width: parent.width
|
||||
visible: (members.numUsersLoaded < members.memberCount) && members.loadingMoreMembers
|
||||
// use the default height if it's visible, otherwise no height at all
|
||||
height: membersLoadingSpinner.height
|
||||
height: membersLoadingSpinner.implicitHeight
|
||||
anchors.margins: Nheko.paddingMedium
|
||||
|
||||
Spinner {
|
||||
id: membersLoadingSpinner
|
||||
|
||||
anchors.centerIn: parent
|
||||
height: visible ? 35 : 0
|
||||
implicitHeight: parent.visible ? 35 : 0
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,15 +6,20 @@
|
|||
#include "MemberList.h"
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Cache_p.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Logging.h"
|
||||
#include "Utils.h"
|
||||
#include "timeline/TimelineViewManager.h"
|
||||
|
||||
MemberList::MemberList(const QString &room_id, QObject *parent)
|
||||
MemberListBackend::MemberListBackend(const QString &room_id, QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
, room_id_{room_id}
|
||||
, powerLevels_{cache::client()
|
||||
->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
|
||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||
.content}
|
||||
{
|
||||
try {
|
||||
info_ = cache::singleRoomInfo(room_id_.toStdString());
|
||||
|
@ -23,7 +28,8 @@ MemberList::MemberList(const QString &room_id, QObject *parent)
|
|||
}
|
||||
|
||||
try {
|
||||
auto members = cache::getMembers(room_id_.toStdString());
|
||||
// HACK: due to QTBUG-1020169, we'll load a big chunk to speed things up
|
||||
auto members = cache::getMembers(room_id_.toStdString(), 0, -1);
|
||||
addUsers(members);
|
||||
numUsersLoaded_ = members.size();
|
||||
} catch (const lmdb::error &e) {
|
||||
|
@ -32,7 +38,7 @@ MemberList::MemberList(const QString &room_id, QObject *parent)
|
|||
}
|
||||
|
||||
void
|
||||
MemberList::addUsers(const std::vector<RoomMember> &members)
|
||||
MemberListBackend::addUsers(const std::vector<RoomMember> &members)
|
||||
{
|
||||
beginInsertRows(QModelIndex{}, m_memberList.count(), m_memberList.count() + members.size() - 1);
|
||||
|
||||
|
@ -46,7 +52,7 @@ MemberList::addUsers(const std::vector<RoomMember> &members)
|
|||
}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
MemberList::roleNames() const
|
||||
MemberListBackend::roleNames() const
|
||||
{
|
||||
return {
|
||||
{Mxid, "mxid"},
|
||||
|
@ -57,7 +63,7 @@ MemberList::roleNames() const
|
|||
}
|
||||
|
||||
QVariant
|
||||
MemberList::data(const QModelIndex &index, int role) const
|
||||
MemberListBackend::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= (int)m_memberList.size() || index.row() < 0)
|
||||
return {};
|
||||
|
@ -80,13 +86,16 @@ MemberList::data(const QModelIndex &index, int role) const
|
|||
else
|
||||
return stat->user_verified;
|
||||
}
|
||||
case Powerlevel:
|
||||
return static_cast<qlonglong>(
|
||||
powerLevels_.user_level(m_memberList[index.row()].first.user_id.toStdString()));
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MemberList::canFetchMore(const QModelIndex &) const
|
||||
MemberListBackend::canFetchMore(const QModelIndex &) const
|
||||
{
|
||||
const size_t numMembers = rowCount();
|
||||
if (numMembers > 1 && numMembers < info_.member_count)
|
||||
|
@ -96,7 +105,7 @@ MemberList::canFetchMore(const QModelIndex &) const
|
|||
}
|
||||
|
||||
void
|
||||
MemberList::fetchMore(const QModelIndex &)
|
||||
MemberListBackend::fetchMore(const QModelIndex &)
|
||||
{
|
||||
loadingMoreMembers_ = true;
|
||||
emit loadingMoreMembersChanged();
|
||||
|
@ -109,3 +118,49 @@ MemberList::fetchMore(const QModelIndex &)
|
|||
loadingMoreMembers_ = false;
|
||||
emit loadingMoreMembersChanged();
|
||||
}
|
||||
|
||||
MemberList::MemberList(const QString &room_id, QObject *parent)
|
||||
: QSortFilterProxyModel{parent}
|
||||
, m_model{room_id, this}
|
||||
{
|
||||
connect(&m_model, &MemberListBackend::roomNameChanged, this, &MemberList::roomNameChanged);
|
||||
connect(
|
||||
&m_model, &MemberListBackend::memberCountChanged, this, &MemberList::memberCountChanged);
|
||||
connect(&m_model, &MemberListBackend::avatarUrlChanged, this, &MemberList::avatarUrlChanged);
|
||||
connect(&m_model, &MemberListBackend::roomIdChanged, this, &MemberList::roomIdChanged);
|
||||
connect(&m_model,
|
||||
&MemberListBackend::numUsersLoadedChanged,
|
||||
this,
|
||||
&MemberList::numUsersLoadedChanged);
|
||||
connect(&m_model,
|
||||
&MemberListBackend::loadingMoreMembersChanged,
|
||||
this,
|
||||
&MemberList::loadingMoreMembersChanged);
|
||||
|
||||
setSourceModel(&m_model);
|
||||
setSortRole(MemberSortRoles::Mxid);
|
||||
sort(0, Qt::AscendingOrder);
|
||||
setDynamicSortFilter(true);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void
|
||||
MemberList::setFilterString(const QString &text)
|
||||
{
|
||||
setFilterRegExp(QRegExp::escape(text));
|
||||
}
|
||||
|
||||
void
|
||||
MemberList::sortBy(const MemberSortRoles role)
|
||||
{
|
||||
setSortRole(role);
|
||||
// Unfortunately, Qt doesn't provide a "setSortOrder" function.
|
||||
sort(0, role == MemberSortRoles::Powerlevel ? Qt::DescendingOrder : Qt::AscendingOrder);
|
||||
}
|
||||
|
||||
bool
|
||||
MemberList::filterAcceptsRow(int source_row, const QModelIndex &) const
|
||||
{
|
||||
return m_model.m_memberList[source_row].first.user_id.contains(filterRegExp()) ||
|
||||
m_model.m_memberList[source_row].first.display_name.contains(filterRegExp());
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <mtx/events/power_levels.hpp>
|
||||
|
||||
#include "CacheStructs.h"
|
||||
|
||||
class MemberList : public QAbstractListModel
|
||||
class MemberListBackend : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -27,8 +30,10 @@ public:
|
|||
DisplayName,
|
||||
AvatarUrl,
|
||||
Trustlevel,
|
||||
Powerlevel,
|
||||
};
|
||||
MemberList(const QString &room_id, QObject *parent = nullptr);
|
||||
|
||||
MemberListBackend(const QString &room_id, QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
|
@ -66,4 +71,56 @@ private:
|
|||
RoomInfo info_;
|
||||
int numUsersLoaded_{0};
|
||||
bool loadingMoreMembers_{false};
|
||||
|
||||
mtx::events::state::PowerLevels powerLevels_;
|
||||
|
||||
friend class MemberList;
|
||||
};
|
||||
|
||||
class MemberList : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
|
||||
Q_PROPERTY(int 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)
|
||||
Q_PROPERTY(bool loadingMoreMembers READ loadingMoreMembers NOTIFY loadingMoreMembersChanged)
|
||||
|
||||
public:
|
||||
enum MemberSortRoles
|
||||
{
|
||||
Mxid = MemberListBackend::Roles::Mxid,
|
||||
DisplayName = MemberListBackend::Roles::DisplayName,
|
||||
Powerlevel = MemberListBackend::Roles::Powerlevel,
|
||||
};
|
||||
Q_ENUM(MemberSortRoles)
|
||||
|
||||
MemberList(const QString &room_id, QObject *parent = nullptr);
|
||||
|
||||
QString roomName() const { return m_model.roomName(); }
|
||||
int memberCount() const { return m_model.memberCount(); }
|
||||
QString avatarUrl() const { return m_model.avatarUrl(); }
|
||||
QString roomId() const { return m_model.roomId(); }
|
||||
int numUsersLoaded() const { return m_model.numUsersLoaded(); }
|
||||
bool loadingMoreMembers() const { return m_model.loadingMoreMembers(); }
|
||||
|
||||
signals:
|
||||
void roomNameChanged();
|
||||
void memberCountChanged();
|
||||
void avatarUrlChanged();
|
||||
void roomIdChanged();
|
||||
void numUsersLoadedChanged();
|
||||
void loadingMoreMembersChanged();
|
||||
|
||||
public slots:
|
||||
void setFilterString(const QString &text);
|
||||
void sortBy(const MemberSortRoles role);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
MemberListBackend m_model;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue