2021-05-30 04:09:21 +03:00
|
|
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
2022-01-01 06:57:53 +03:00
|
|
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
2023-01-02 06:25:33 +03:00
|
|
|
// SPDX-FileCopyrightText: 2023 Nheko Contributors
|
2021-05-30 04:09:21 +03:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#include "MemberList.h"
|
|
|
|
|
|
|
|
#include "Cache.h"
|
2022-04-23 02:59:40 +03:00
|
|
|
#include "Cache_p.h"
|
2021-05-30 04:09:21 +03:00
|
|
|
#include "ChatPage.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "Logging.h"
|
|
|
|
#include "Utils.h"
|
|
|
|
#include "timeline/TimelineViewManager.h"
|
|
|
|
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::MemberListBackend(const QString &room_id, QObject *parent)
|
2021-05-30 04:09:21 +03:00
|
|
|
: QAbstractListModel{parent}
|
|
|
|
, room_id_{room_id}
|
2022-04-23 02:59:40 +03:00
|
|
|
, powerLevels_{cache::client()
|
|
|
|
->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
|
|
|
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
|
|
|
.content}
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
try {
|
|
|
|
info_ = cache::singleRoomInfo(room_id_.toStdString());
|
|
|
|
} catch (const lmdb::error &) {
|
|
|
|
nhlog::db()->warn("failed to retrieve room info from cache: {}", room_id_.toStdString());
|
|
|
|
}
|
2021-05-30 04:09:21 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
try {
|
2022-04-23 02:59:40 +03:00
|
|
|
// HACK: due to QTBUG-1020169, we'll load a big chunk to speed things up
|
|
|
|
auto members = cache::getMembers(room_id_.toStdString(), 0, -1);
|
2021-09-18 01:22:33 +03:00
|
|
|
addUsers(members);
|
2022-10-02 13:31:03 +03:00
|
|
|
numUsersLoaded_ = (int)members.size();
|
2021-09-18 01:22:33 +03:00
|
|
|
} catch (const lmdb::error &e) {
|
|
|
|
nhlog::db()->critical("Failed to retrieve members from cache: {}", e.what());
|
|
|
|
}
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::addUsers(const std::vector<RoomMember> &members)
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2022-10-04 00:26:32 +03:00
|
|
|
auto thisRoom = ChatPage::instance()->timelineManager()->rooms()->getRoomById(room_id_);
|
|
|
|
if (thisRoom.isNull()) {
|
|
|
|
nhlog::ui()->error("Could not load the current room");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-02 13:31:03 +03:00
|
|
|
beginInsertRows(
|
|
|
|
QModelIndex{}, m_memberList.count(), m_memberList.count() + (int)members.size() - 1);
|
2021-05-30 04:09:21 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
for (const auto &member : members)
|
2022-10-04 00:26:32 +03:00
|
|
|
m_memberList.push_back({member, thisRoom->avatarUrl(member.user_id)});
|
2021-05-30 04:09:21 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
endInsertRows();
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QHash<int, QByteArray>
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::roleNames() const
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
return {
|
|
|
|
{Mxid, "mxid"},
|
|
|
|
{DisplayName, "displayName"},
|
|
|
|
{AvatarUrl, "avatarUrl"},
|
|
|
|
{Trustlevel, "trustlevel"},
|
2022-05-07 03:30:16 +03:00
|
|
|
{Powerlevel, "powerlevel"},
|
2021-09-18 01:22:33 +03:00
|
|
|
};
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::data(const QModelIndex &index, int role) const
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
if (!index.isValid() || index.row() >= (int)m_memberList.size() || index.row() < 0)
|
|
|
|
return {};
|
2021-05-30 04:09:21 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
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;
|
|
|
|
case Trustlevel: {
|
|
|
|
auto stat =
|
|
|
|
cache::verificationStatus(m_memberList[index.row()].first.user_id.toStdString());
|
2021-08-14 00:58:26 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
if (!stat)
|
|
|
|
return crypto::Unverified;
|
|
|
|
if (stat->unverified_device_count)
|
|
|
|
return crypto::Unverified;
|
|
|
|
else
|
|
|
|
return stat->user_verified;
|
|
|
|
}
|
2022-04-23 02:59:40 +03:00
|
|
|
case Powerlevel:
|
|
|
|
return static_cast<qlonglong>(
|
|
|
|
powerLevels_.user_level(m_memberList[index.row()].first.user_id.toStdString()));
|
2021-09-18 01:22:33 +03:00
|
|
|
default:
|
|
|
|
return {};
|
|
|
|
}
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
|
|
|
|
2021-06-11 03:13:12 +03:00
|
|
|
bool
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::canFetchMore(const QModelIndex &) const
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
const size_t numMembers = rowCount();
|
|
|
|
if (numMembers > 1 && numMembers < info_.member_count)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-04-23 02:59:40 +03:00
|
|
|
MemberListBackend::fetchMore(const QModelIndex &)
|
2021-05-30 04:09:21 +03:00
|
|
|
{
|
2021-09-18 01:22:33 +03:00
|
|
|
loadingMoreMembers_ = true;
|
|
|
|
emit loadingMoreMembersChanged();
|
2021-07-19 21:49:57 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
auto members = cache::getMembers(room_id_.toStdString(), rowCount());
|
|
|
|
addUsers(members);
|
2022-10-02 13:31:03 +03:00
|
|
|
numUsersLoaded_ += (int)members.size();
|
2021-09-18 01:22:33 +03:00
|
|
|
emit numUsersLoadedChanged();
|
2021-07-19 21:49:57 +03:00
|
|
|
|
2021-09-18 01:22:33 +03:00
|
|
|
loadingMoreMembers_ = false;
|
|
|
|
emit loadingMoreMembersChanged();
|
2021-05-30 04:09:21 +03:00
|
|
|
}
|
2022-04-23 02:59:40 +03:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2022-04-23 15:53:36 +03:00
|
|
|
filterString = text;
|
2022-04-23 04:01:20 +03:00
|
|
|
setFilterFixedString(text);
|
2022-04-23 02:59:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2022-08-13 19:13:42 +03:00
|
|
|
return m_model.m_memberList[source_row].first.user_id.contains(filterString,
|
|
|
|
Qt::CaseInsensitive) ||
|
|
|
|
m_model.m_memberList[source_row].first.display_name.contains(filterString,
|
|
|
|
Qt::CaseInsensitive);
|
2022-04-23 02:59:40 +03:00
|
|
|
}
|