mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-27 21:48:48 +03:00
add user search to invite dialog
This commit is contained in:
parent
6529240be8
commit
b599f5c0c6
9 changed files with 365 additions and 67 deletions
|
@ -493,6 +493,8 @@ set(SRC_FILES
|
||||||
src/SingleImagePackModel.h
|
src/SingleImagePackModel.h
|
||||||
src/TrayIcon.cpp
|
src/TrayIcon.cpp
|
||||||
src/TrayIcon.h
|
src/TrayIcon.h
|
||||||
|
src/UserDirectoryModel.cpp
|
||||||
|
src/UserDirectoryModel.h
|
||||||
src/UserSettingsPage.cpp
|
src/UserSettingsPage.cpp
|
||||||
src/UserSettingsPage.h
|
src/UserSettingsPage.h
|
||||||
src/UsersModel.cpp
|
src/UsersModel.cpp
|
||||||
|
@ -594,14 +596,14 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG d187c63a27710fa87a44ab44d43b7cfa2023132a
|
GIT_TAG d187c63a27710fa87a44ab44d43b7cfa2023132a
|
||||||
)
|
)
|
||||||
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
FetchContent_MakeAvailable(MatrixClient)
|
FetchContent_MakeAvailable(MatrixClient)
|
||||||
else()
|
else()
|
||||||
find_package(MatrixClient 0.8.1 REQUIRED)
|
find_package(MatrixClient 0.8.3 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (VOIP)
|
if (VOIP)
|
||||||
|
|
|
@ -33,6 +33,10 @@ Pane {
|
||||||
id: publicRooms
|
id: publicRooms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UserDirectoryModel {
|
||||||
|
id: userDirectory
|
||||||
|
}
|
||||||
|
|
||||||
//Timer {
|
//Timer {
|
||||||
// onTriggered: gc()
|
// onTriggered: gc()
|
||||||
// interval: 1000
|
// interval: 1000
|
||||||
|
|
|
@ -15,17 +15,26 @@ ApplicationWindow {
|
||||||
property string roomId
|
property string roomId
|
||||||
property string plainRoomName
|
property string plainRoomName
|
||||||
property InviteesModel invitees
|
property InviteesModel invitees
|
||||||
|
property var friendsCompleter
|
||||||
|
property var profile
|
||||||
|
minimumWidth: 500
|
||||||
|
|
||||||
function addInvite() {
|
Component.onCompleted: {
|
||||||
if (inviteeEntry.isValidMxid) {
|
friendsCompleter = TimelineManager.completerFor("user", "friends")
|
||||||
invitees.addUser(inviteeEntry.text);
|
}
|
||||||
inviteeEntry.clear();
|
|
||||||
}
|
function addInvite(mxid) {
|
||||||
|
if (mxid.match("@.+?:.{3,}")) {
|
||||||
|
invitees.addUser(mxid);
|
||||||
|
if (mxid == inviteeEntry.text)
|
||||||
|
inviteeEntry.clear();
|
||||||
|
} else
|
||||||
|
console.log("invalid mxid: " + mxid)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanUpAndClose() {
|
function cleanUpAndClose() {
|
||||||
if (inviteeEntry.isValidMxid)
|
if (inviteeEntry.isValidMxid)
|
||||||
addInvite();
|
addInvite(inviteeEntry.text);
|
||||||
|
|
||||||
invitees.accept();
|
invitees.accept();
|
||||||
close();
|
close();
|
||||||
|
@ -72,7 +81,7 @@ ApplicationWindow {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (isValidMxid)
|
if (isValidMxid)
|
||||||
addInvite();
|
addInvite(text);
|
||||||
|
|
||||||
}
|
}
|
||||||
Component.onCompleted: forceActiveFocus()
|
Component.onCompleted: forceActiveFocus()
|
||||||
|
@ -82,85 +91,198 @@ ApplicationWindow {
|
||||||
cleanUpAndClose();
|
cleanUpAndClose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
onTextChanged: {
|
||||||
|
searchTimer.restart()
|
||||||
|
if(isValidMxid) {
|
||||||
|
profile = TimelineManager.getGlobalUserProfile(text);
|
||||||
|
} else
|
||||||
|
profile = null;
|
||||||
|
}
|
||||||
|
Timer {
|
||||||
|
id: searchTimer
|
||||||
|
|
||||||
|
interval: 350
|
||||||
|
onTriggered: {
|
||||||
|
userSearch.model.setSearchString(parent.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
CheckBox {
|
||||||
text: qsTr("Add")
|
id: searchOnServer
|
||||||
enabled: inviteeEntry.isValidMxid
|
text: qsTr("Search on Server")
|
||||||
onClicked: addInvite()
|
checked: false
|
||||||
|
onClicked: userSearch.model.setSearchString(inviteeEntry.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
RowLayout {
|
||||||
ListView {
|
ItemDelegate {
|
||||||
id: inviteesList
|
visible: inviteeEntry.isValidMxid
|
||||||
|
id: del3
|
||||||
Layout.fillWidth: true
|
Layout.preferredWidth: inviteDialogRoot.width/2
|
||||||
Layout.fillHeight: true
|
Layout.alignment: Qt.AlignTop
|
||||||
model: invitees
|
Layout.preferredHeight: layout3.implicitHeight + Nheko.paddingSmall * 2
|
||||||
|
onClicked: addInvite(inviteeEntry.text)
|
||||||
delegate: ItemDelegate {
|
|
||||||
id: del
|
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
width: ListView.view.width
|
|
||||||
height: layout.implicitHeight + Nheko.paddingSmall * 2
|
|
||||||
onClicked: TimelineManager.openGlobalUserProfile(model.mxid)
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: del.hovered ? Nheko.colors.dark : inviteDialogRoot.color
|
color: del3.hovered ? Nheko.colors.dark : inviteDialogRoot.color
|
||||||
|
clip: true
|
||||||
}
|
}
|
||||||
|
GridLayout {
|
||||||
RowLayout {
|
id: layout3
|
||||||
id: layout
|
|
||||||
|
|
||||||
spacing: Nheko.paddingMedium
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: del.width - Nheko.paddingSmall * 2
|
width: del3.width - Nheko.paddingSmall * 2
|
||||||
|
rows: 2
|
||||||
|
columns: 2
|
||||||
|
rowSpacing: Nheko.paddingSmall
|
||||||
|
columnSpacing: Nheko.paddingMedium
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
width: Nheko.avatarSize
|
Layout.rowSpan: 2
|
||||||
height: Nheko.avatarSize
|
Layout.preferredWidth: Nheko.avatarSize
|
||||||
userid: model.mxid
|
Layout.preferredHeight: Nheko.avatarSize
|
||||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
Layout.alignment: Qt.AlignLeft
|
||||||
displayName: model.displayName
|
userid: inviteeEntry.text
|
||||||
|
url: profile? profile.avatarUrl.replace("mxc://", "image://MxcImage/") : ""
|
||||||
|
displayName: profile? profile.displayName : ""
|
||||||
enabled: false
|
enabled: false
|
||||||
}
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: profile? profile.displayName : ""
|
||||||
|
color: TimelineManager.userColor(inviteeEntry.text, Nheko.colors.window)
|
||||||
|
font.pointSize: fontMetrics.font.pointSize
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Label {
|
||||||
spacing: Nheko.paddingSmall
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: inviteeEntry.text
|
||||||
|
color: Nheko.colors.buttonText
|
||||||
|
font.pointSize: fontMetrics.font.pointSize * 0.9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListView {
|
||||||
|
visible: !inviteeEntry.isValidMxid
|
||||||
|
id: userSearch
|
||||||
|
model: searchOnServer.checked? userDirectory : friendsCompleter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
clip: true
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
id: del2
|
||||||
|
width: ListView.view.width
|
||||||
|
height: layout2.implicitHeight + Nheko.paddingSmall * 2
|
||||||
|
onClicked: addInvite(model.userid)
|
||||||
|
background: Rectangle {
|
||||||
|
color: del2.hovered ? Nheko.colors.dark : inviteDialogRoot.color
|
||||||
|
}
|
||||||
|
GridLayout {
|
||||||
|
id: layout2
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: del2.width - Nheko.paddingSmall * 2
|
||||||
|
rows: 2
|
||||||
|
columns: 2
|
||||||
|
rowSpacing: Nheko.paddingSmall
|
||||||
|
columnSpacing: Nheko.paddingMedium
|
||||||
|
|
||||||
|
Avatar {
|
||||||
|
Layout.rowSpan: 2
|
||||||
|
Layout.preferredWidth: Nheko.avatarSize
|
||||||
|
Layout.preferredHeight: Nheko.avatarSize
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
userid: model.userid
|
||||||
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
displayName: model.displayName
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
Label {
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
text: model.displayName
|
text: model.displayName
|
||||||
color: TimelineManager.userColor(model ? model.mxid : "", del.background.color)
|
color: TimelineManager.userColor(model.userid, Nheko.colors.window)
|
||||||
font.pointSize: fontMetrics.font.pointSize
|
font.pointSize: fontMetrics.font.pointSize
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: model.userid
|
||||||
|
color: Nheko.colors.buttonText
|
||||||
|
font.pointSize: fontMetrics.font.pointSize * 0.9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListView {
|
||||||
|
id: inviteesList
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
model: invitees
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
id: del
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
width: ListView.view.width
|
||||||
|
height: layout.implicitHeight + Nheko.paddingSmall * 2
|
||||||
|
onClicked: TimelineManager.openGlobalUserProfile(model.mxid)
|
||||||
|
background: Rectangle {
|
||||||
|
color: del.hovered ? Nheko.colors.dark : inviteDialogRoot.color
|
||||||
|
}
|
||||||
|
GridLayout {
|
||||||
|
id: layout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: del.width - Nheko.paddingSmall * 2
|
||||||
|
rows: 2
|
||||||
|
columns: 3
|
||||||
|
rowSpacing: Nheko.paddingSmall
|
||||||
|
columnSpacing: Nheko.paddingMedium
|
||||||
|
|
||||||
|
Avatar {
|
||||||
|
Layout.rowSpan: 2
|
||||||
|
Layout.preferredWidth: Nheko.avatarSize
|
||||||
|
Layout.preferredHeight: Nheko.avatarSize
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
userid: model.mxid
|
||||||
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
displayName: model.displayName
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: model.displayName
|
||||||
|
color: TimelineManager.userColor(model.mxid, Nheko.colors.window)
|
||||||
|
font.pointSize: fontMetrics.font.pointSize
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButton {
|
||||||
|
Layout.rowSpan: 2
|
||||||
|
id: removeButton
|
||||||
|
image: ":/icons/icons/ui/dismiss.svg"
|
||||||
|
onClicked: invitees.removeUser(model.mxid)
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
text: model.mxid
|
text: model.mxid
|
||||||
color: del.hovered ? Nheko.colors.brightText : Nheko.colors.buttonText
|
color: Nheko.colors.buttonText
|
||||||
font.pointSize: fontMetrics.font.pointSize * 0.9
|
font.pointSize: fontMetrics.font.pointSize * 0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
CursorShape {
|
||||||
Layout.fillWidth: true
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageButton {
|
|
||||||
image: ":/icons/icons/ui/dismiss.svg"
|
|
||||||
onClicked: invitees.removeUser(model.mxid)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CursorShape {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "RoomsModel.h"
|
#include "RoomsModel.h"
|
||||||
#include "SingleImagePackModel.h"
|
#include "SingleImagePackModel.h"
|
||||||
#include "TrayIcon.h"
|
#include "TrayIcon.h"
|
||||||
|
#include "UserDirectoryModel.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
#include "UsersModel.h"
|
#include "UsersModel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
@ -69,6 +70,7 @@ Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
|
||||||
Q_DECLARE_METATYPE(std::vector<mtx::responses::PublicRoomsChunk>)
|
Q_DECLARE_METATYPE(std::vector<mtx::responses::PublicRoomsChunk>)
|
||||||
Q_DECLARE_METATYPE(mtx::responses::PublicRoom)
|
Q_DECLARE_METATYPE(mtx::responses::PublicRoom)
|
||||||
Q_DECLARE_METATYPE(mtx::responses::Profile)
|
Q_DECLARE_METATYPE(mtx::responses::Profile)
|
||||||
|
Q_DECLARE_METATYPE(mtx::responses::User)
|
||||||
|
|
||||||
MainWindow *MainWindow::instance_ = nullptr;
|
MainWindow *MainWindow::instance_ = nullptr;
|
||||||
|
|
||||||
|
@ -147,6 +149,7 @@ MainWindow::registerQmlTypes()
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationRequest>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationRequest>();
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationStart>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationStart>();
|
||||||
qRegisterMetaType<mtx::responses::PublicRoom>();
|
qRegisterMetaType<mtx::responses::PublicRoom>();
|
||||||
|
qRegisterMetaType<mtx::responses::User>();
|
||||||
qRegisterMetaType<mtx::responses::Profile>();
|
qRegisterMetaType<mtx::responses::Profile>();
|
||||||
qRegisterMetaType<CombinedImagePackModel *>();
|
qRegisterMetaType<CombinedImagePackModel *>();
|
||||||
qRegisterMetaType<RoomSettingsAllowedRoomsModel *>();
|
qRegisterMetaType<RoomSettingsAllowedRoomsModel *>();
|
||||||
|
@ -154,7 +157,9 @@ MainWindow::registerQmlTypes()
|
||||||
qRegisterMetaType<std::vector<DeviceInfo>>();
|
qRegisterMetaType<std::vector<DeviceInfo>>();
|
||||||
|
|
||||||
qRegisterMetaType<std::vector<mtx::responses::PublicRoomsChunk>>();
|
qRegisterMetaType<std::vector<mtx::responses::PublicRoomsChunk>>();
|
||||||
|
qRegisterMetaType<std::vector<mtx::responses::User>>();
|
||||||
|
|
||||||
|
qRegisterMetaType<mtx::responses::User>();
|
||||||
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
|
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
|
||||||
"im.nheko",
|
"im.nheko",
|
||||||
1,
|
1,
|
||||||
|
@ -184,6 +189,7 @@ MainWindow::registerQmlTypes()
|
||||||
qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage");
|
qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage");
|
||||||
qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia");
|
qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia");
|
||||||
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
|
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
|
||||||
|
qmlRegisterType<UserDirectoryModel>("im.nheko", 1, 0, "UserDirectoryModel");
|
||||||
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
||||||
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
||||||
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
||||||
|
|
|
@ -57,7 +57,10 @@ public:
|
||||||
void showChatPage();
|
void showChatPage();
|
||||||
|
|
||||||
#ifdef NHEKO_DBUS_SYS
|
#ifdef NHEKO_DBUS_SYS
|
||||||
bool dbusAvailable() const { return dbusAvailable_; }
|
bool dbusAvailable() const
|
||||||
|
{
|
||||||
|
return dbusAvailable_;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q_INVOKABLE void addPerRoomWindow(const QString &room, QWindow *window);
|
Q_INVOKABLE void addPerRoomWindow(const QString &room, QWindow *window);
|
||||||
|
|
87
src/UserDirectoryModel.cpp
Normal file
87
src/UserDirectoryModel.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "UserDirectoryModel.h"
|
||||||
|
|
||||||
|
#include "Cache.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
#include "MatrixClient.h"
|
||||||
|
#include "mtx/responses/users.hpp"
|
||||||
|
|
||||||
|
UserDirectoryModel::UserDirectoryModel(QObject *parent)
|
||||||
|
: QAbstractListModel{parent}
|
||||||
|
{
|
||||||
|
connect(this,
|
||||||
|
&UserDirectoryModel::fetchedSearchResults,
|
||||||
|
this,
|
||||||
|
&UserDirectoryModel::displaySearchResults,
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
endResetModel();
|
||||||
|
searchingUsers_ = true;
|
||||||
|
emit searchingUsersChanged();
|
||||||
|
http::client()->search_user_directory(
|
||||||
|
userSearchString_,
|
||||||
|
[this](const mtx::responses::Users &res, mtx::http::RequestErr err) {
|
||||||
|
searchingUsers_ = false;
|
||||||
|
emit searchingUsersChanged();
|
||||||
|
|
||||||
|
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 fetchedSearchResults(res.results);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
results_ = results;
|
||||||
|
if (results_.empty()) {
|
||||||
|
nhlog::net()->error("mtxclient helper thread yielded empty chunk!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beginInsertRows(QModelIndex(), 0, static_cast<int>(results_.size()) - 1);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
55
src/UserDirectoryModel.h
Normal file
55
src/UserDirectoryModel.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
// SPDX-FileCopyrightText: 2022 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 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<mtx::responses::User> results_;
|
||||||
|
std::string userSearchString_;
|
||||||
|
bool searchingUsers_{false};
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void searchingUsersChanged();
|
||||||
|
void fetchedSearchResults(std::vector<mtx::responses::User> results);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setSearchString(const QString &f);
|
||||||
|
bool searchingUsers() const { return searchingUsers_; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void displaySearchResults(std::vector<mtx::responses::User> results);
|
||||||
|
};
|
|
@ -8,6 +8,7 @@
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
|
#include "Cache_p.h"
|
||||||
#include "CompletionModelRoles.h"
|
#include "CompletionModelRoles.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
|
|
||||||
|
@ -15,10 +16,29 @@ UsersModel::UsersModel(const std::string &roomId, QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, room_id(roomId)
|
, room_id(roomId)
|
||||||
{
|
{
|
||||||
roomMembers_ = cache::roomMembers(roomId);
|
// obviously, "friends" isn't a room, but I felt this was the least invasive way
|
||||||
for (const auto &m : roomMembers_) {
|
if (roomId == "friends") {
|
||||||
displayNames.push_back(QString::fromStdString(cache::displayName(room_id, m)));
|
auto e = cache::client()->getAccountData(mtx::events::EventType::Direct);
|
||||||
userids.push_back(QString::fromStdString(m));
|
if (e) {
|
||||||
|
if (auto event =
|
||||||
|
std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>(
|
||||||
|
&e.value())) {
|
||||||
|
for (const auto &[userId, roomIds] : event->content.user_to_rooms) {
|
||||||
|
displayNames.push_back(
|
||||||
|
QString::fromStdString(cache::displayName(roomIds[0], userId)));
|
||||||
|
userids.push_back(QString::fromStdString(userId));
|
||||||
|
avatarUrls.push_back(cache::avatarUrl(QString::fromStdString(roomIds[0]),
|
||||||
|
QString::fromStdString(userId)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const auto &m : cache::roomMembers(roomId)) {
|
||||||
|
displayNames.push_back(QString::fromStdString(cache::displayName(room_id, m)));
|
||||||
|
userids.push_back(QString::fromStdString(m));
|
||||||
|
avatarUrls.push_back(
|
||||||
|
cache::avatarUrl(QString::fromStdString(room_id), QString::fromStdString(m)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +78,7 @@ UsersModel::data(const QModelIndex &index, int role) const
|
||||||
case CompletionModel::SearchRole2:
|
case CompletionModel::SearchRole2:
|
||||||
return userids[index.row()];
|
return userids[index.row()];
|
||||||
case Roles::AvatarUrl:
|
case Roles::AvatarUrl:
|
||||||
return cache::avatarUrl(QString::fromStdString(room_id),
|
return avatarUrls[index.row()];
|
||||||
QString::fromStdString(roomMembers_[index.row()]));
|
|
||||||
case Roles::UserID:
|
case Roles::UserID:
|
||||||
return userids[index.row()].toHtmlEscaped();
|
return userids[index.row()].toHtmlEscaped();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ public:
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
{
|
{
|
||||||
(void)parent;
|
(void)parent;
|
||||||
return (int)roomMembers_.size();
|
return (int)userids.size();
|
||||||
}
|
}
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string room_id;
|
std::string room_id;
|
||||||
std::vector<std::string> roomMembers_;
|
std::vector<QString> avatarUrls;
|
||||||
std::vector<QString> displayNames;
|
std::vector<QString> displayNames;
|
||||||
std::vector<QString> userids;
|
std::vector<QString> userids;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue