mirror of https://github.com/Nheko-Reborn/nheko
add user search to invite dialog (#1253)
parent
3abb49c4a2
commit
5ed3bfc8f8
@ -0,0 +1,53 @@ |
||||
// SPDX-FileCopyrightText: 2021 Nheko Contributors |
||||
// SPDX-FileCopyrightText: 2022 Nheko Contributors |
||||
// SPDX-FileCopyrightText: 2023 Nheko Contributors |
||||
// |
||||
// SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
||||
import ".." |
||||
import QtQuick 2.12 |
||||
import QtQuick.Controls 2.12 |
||||
import QtQuick.Layouts 1.12 |
||||
import im.nheko 1.0 |
||||
|
||||
ItemDelegate { |
||||
property alias bgColor: background.color |
||||
property alias userid: avatar.userid |
||||
property alias displayName: avatar.displayName |
||||
property string avatarUrl |
||||
implicitHeight: layout.implicitHeight + Nheko.paddingSmall * 2 |
||||
background: Rectangle {id: background} |
||||
GridLayout { |
||||
id: layout |
||||
anchors.centerIn: parent |
||||
width: parent.width - Nheko.paddingSmall * 2 |
||||
rows: 2 |
||||
columns: 2 |
||||
rowSpacing: Nheko.paddingSmall |
||||
columnSpacing: Nheko.paddingMedium |
||||
|
||||
Avatar { |
||||
id: avatar |
||||
Layout.rowSpan: 2 |
||||
Layout.preferredWidth: Nheko.avatarSize |
||||
Layout.preferredHeight: Nheko.avatarSize |
||||
Layout.alignment: Qt.AlignLeft |
||||
url: avatarUrl.replace("mxc://", "image://MxcImage/") |
||||
enabled: false |
||||
} |
||||
Label { |
||||
Layout.fillWidth: true |
||||
text: displayName |
||||
color: TimelineManager.userColor(userid, Nheko.colors.window) |
||||
font.pointSize: fontMetrics.font.pointSize |
||||
} |
||||
|
||||
Label { |
||||
Layout.fillWidth: true |
||||
Layout.alignment: Qt.AlignTop |
||||
text: userid |
||||
color: Nheko.colors.buttonText |
||||
font.pointSize: fontMetrics.font.pointSize * 0.9 |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,105 @@ |
||||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||
// SPDX-FileCopyrightText: 2023 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "UserDirectoryModel.h" |
||||
|
||||
#include "Cache.h" |
||||
#include "Logging.h" |
||||
#include <QSharedPointer> |
||||
#include "MatrixClient.h" |
||||
#include "mtx/responses/users.hpp" |
||||
|
||||
UserDirectoryModel::UserDirectoryModel(QObject *parent) |
||||
: QAbstractListModel{parent} |
||||
{ |
||||
} |
||||
|
||||
QHash<int, QByteArray> |
||||
UserDirectoryModel::roleNames() const |
||||
{ |
||||
return { |
||||
{Roles::DisplayName, "displayName"}, |
||||
{Roles::Mxid, "userid"}, |
||||
{Roles::AvatarUrl, "avatarUrl"}, |
||||
}; |
||||
} |
||||
|
||||
void |
||||
UserDirectoryModel::setSearchString(const QString &f) |
||||
{ |
||||
userSearchString_ = f.toStdString(); |
||||
nhlog::ui()->debug("Received user directory query: {}", userSearchString_); |
||||
beginResetModel(); |
||||
results_.clear(); |
||||
if (userSearchString_ == "") |
||||
nhlog::ui()->debug("Rejecting empty search string"); |
||||
else |
||||
canFetchMore_ = true; |
||||
endResetModel(); |
||||
} |
||||
|
||||
void |
||||
UserDirectoryModel::fetchMore(const QModelIndex &) |
||||
{ |
||||
if (!canFetchMore_) |
||||
return; |
||||
|
||||
nhlog::net()->debug("Fetching users from mtxclient..."); |
||||
std::string searchTerm = userSearchString_; |
||||
searchingUsers_ = true; |
||||
emit searchingUsersChanged(); |
||||
auto job = QSharedPointer<FetchUsersFromDirectoryJob>::create(); |
||||
connect(job.data(), |
||||
&FetchUsersFromDirectoryJob::fetchedSearchResults, |
||||
this, |
||||
&UserDirectoryModel::displaySearchResults); |
||||
http::client()->search_user_directory( |
||||
searchTerm, |
||||
[job, searchTerm](const mtx::responses::Users &res, mtx::http::RequestErr err) { |
||||
if (err) { |
||||
nhlog::net()->error("Failed to retrieve users from mtxclient - {} - {} - {}", |
||||
mtx::errors::to_string(err->matrix_error.errcode), |
||||
err->matrix_error.error, |
||||
err->parse_error); |
||||
} else { |
||||
emit job->fetchedSearchResults(res.results, searchTerm); |
||||
} |
||||
}, |
||||
50); |
||||
} |
||||
|
||||
QVariant |
||||
UserDirectoryModel::data(const QModelIndex &index, int role) const |
||||
{ |
||||
if (!index.isValid() || index.row() >= (int)results_.size() || index.row() < 0) |
||||
return {}; |
||||
switch (role) { |
||||
case Roles::DisplayName: |
||||
return QString::fromStdString(results_[index.row()].display_name); |
||||
case Roles::Mxid: |
||||
return QString::fromStdString(results_[index.row()].user_id); |
||||
case Roles::AvatarUrl: |
||||
return QString::fromStdString(results_[index.row()].avatar_url); |
||||
} |
||||
return {}; |
||||
} |
||||
|
||||
void |
||||
UserDirectoryModel::displaySearchResults(std::vector<mtx::responses::User> results, const std::string &searchTerm) |
||||
{ |
||||
if (searchTerm != this->userSearchString_) |
||||
return; |
||||
searchingUsers_ = false; |
||||
emit searchingUsersChanged(); |
||||
if (results.empty()) { |
||||
nhlog::net()->debug("mtxclient helper thread yielded no results!"); |
||||
return; |
||||
} |
||||
beginInsertRows(QModelIndex(), 0, static_cast<int>(results.size()) - 1); |
||||
results_ = results; |
||||
endInsertRows(); |
||||
canFetchMore_ = false; |
||||
} |
@ -0,0 +1,69 @@ |
||||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||
// SPDX-FileCopyrightText: 2023 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once |
||||
|
||||
#include <QAbstractListModel> |
||||
#include <QString> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include <mtx/responses/users.hpp> |
||||
|
||||
class FetchUsersFromDirectoryJob final : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit FetchUsersFromDirectoryJob(QObject *p = nullptr) |
||||
: QObject(p) |
||||
{ |
||||
} |
||||
signals: |
||||
void fetchedSearchResults(std::vector<mtx::responses::User> results, const std::string &searchTerm); |
||||
}; |
||||
class UserDirectoryModel : public QAbstractListModel |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
Q_PROPERTY(bool searchingUsers READ searchingUsers NOTIFY searchingUsersChanged) |
||||
|
||||
public: |
||||
explicit UserDirectoryModel(QObject *parent = nullptr); |
||||
|
||||
enum Roles |
||||
{ |
||||
DisplayName, |
||||
Mxid, |
||||
AvatarUrl, |
||||
}; |
||||
QHash<int, QByteArray> roleNames() const override; |
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override; |
||||
|
||||
inline int rowCount(const QModelIndex &parent = QModelIndex()) const override |
||||
{ |
||||
(void)parent; |
||||
return static_cast<int>(results_.size()); |
||||
} |
||||
bool canFetchMore(const QModelIndex &) const override { return canFetchMore_; } |
||||
void fetchMore(const QModelIndex &) override; |
||||
|
||||
private: |
||||
std::vector<mtx::responses::User> results_; |
||||
std::string userSearchString_; |
||||
bool searchingUsers_{false}; |
||||
bool canFetchMore_{false}; |
||||
|
||||
signals: |
||||
void searchingUsersChanged(); |
||||
|
||||
public slots: |
||||
void setSearchString(const QString &f); |
||||
bool searchingUsers() const { return searchingUsers_; } |
||||
|
||||
private slots: |
||||
void displaySearchResults(std::vector<mtx::responses::User> results, const std::string &searchTerm); |
||||
}; |
Loading…
Reference in new issue