File indexing completed on 2024-12-08 07:33:47

0001 // SPDX-FileCopyrightText: 2018-2020 Black Hat <bhat@encom.eu.org>
0002 // SPDX-License-Identifier: GPL-3.0-only
0003 
0004 #include "userlistmodel.h"
0005 
0006 #include <QGuiApplication>
0007 
0008 #include <Quotient/connection.h>
0009 #include <Quotient/events/roompowerlevelsevent.h>
0010 
0011 #include "neochatroom.h"
0012 
0013 using namespace Quotient;
0014 
0015 UserListModel::UserListModel(QObject *parent)
0016     : QAbstractListModel(parent)
0017     , m_currentRoom(nullptr)
0018 {
0019 }
0020 
0021 void UserListModel::setRoom(NeoChatRoom *room)
0022 {
0023     if (m_currentRoom == room) {
0024         return;
0025     }
0026 
0027     if (m_currentRoom) {
0028         m_currentRoom->disconnect(this);
0029     }
0030     m_currentRoom = room;
0031 
0032     if (m_currentRoom) {
0033         connect(m_currentRoom, &Room::userAdded, this, &UserListModel::userAdded);
0034         connect(m_currentRoom, &Room::userRemoved, this, &UserListModel::userRemoved);
0035         connect(m_currentRoom, &Room::memberAboutToRename, this, &UserListModel::userRemoved);
0036         connect(m_currentRoom, &Room::memberRenamed, this, &UserListModel::userAdded);
0037         connect(m_currentRoom, &Room::changed, this, &UserListModel::refreshAllUsers);
0038     }
0039 
0040     refreshAllUsers();
0041     Q_EMIT roomChanged();
0042 }
0043 
0044 NeoChatRoom *UserListModel::room() const
0045 {
0046     return m_currentRoom;
0047 }
0048 
0049 Quotient::User *UserListModel::userAt(QModelIndex index) const
0050 {
0051     if (index.row() < 0 || index.row() >= m_users.size()) {
0052         return nullptr;
0053     }
0054     return m_users.at(index.row());
0055 }
0056 
0057 QVariant UserListModel::data(const QModelIndex &index, int role) const
0058 {
0059     if (!index.isValid()) {
0060         return QVariant();
0061     }
0062 
0063     if (index.row() >= m_users.count()) {
0064         qDebug() << "UserListModel, something's wrong: index.row() >= "
0065                     "users.count()";
0066         return {};
0067     }
0068     auto user = m_users.at(index.row());
0069     if (role == DisplayNameRole) {
0070         return user->displayname(m_currentRoom);
0071     }
0072     if (role == UserIdRole) {
0073         return user->id();
0074     }
0075     if (role == AvatarRole) {
0076         return m_currentRoom->avatarForMember(user);
0077     }
0078     if (role == ObjectRole) {
0079         return QVariant::fromValue(user);
0080     }
0081     if (role == PowerLevelRole) {
0082         auto plEvent = m_currentRoom->currentState().get<RoomPowerLevelsEvent>();
0083         if (!plEvent) {
0084             return 0;
0085         }
0086         return plEvent->powerLevelForUser(user->id());
0087     }
0088     if (role == PowerLevelStringRole) {
0089         auto pl = m_currentRoom->currentState().get<RoomPowerLevelsEvent>();
0090         // User might not in the room yet, in this case pl can be nullptr.
0091         // e.g. When invited but user not accepted or denied the invitation.
0092         if (!pl) {
0093             return QStringLiteral("Not Available");
0094         }
0095 
0096         auto userPl = pl->powerLevelForUser(user->id());
0097 
0098         switch (userPl) {
0099         case 0:
0100             return QStringLiteral("Member");
0101         case 50:
0102             return QStringLiteral("Moderator");
0103         case 100:
0104             return QStringLiteral("Admin");
0105         default:
0106             return QStringLiteral("Custom");
0107         }
0108     }
0109 
0110     return {};
0111 }
0112 
0113 int UserListModel::rowCount(const QModelIndex &parent) const
0114 {
0115     if (parent.isValid()) {
0116         return 0;
0117     }
0118     return m_users.count();
0119 }
0120 
0121 bool UserListModel::event(QEvent *event)
0122 {
0123     if (event->type() == QEvent::ApplicationPaletteChange) {
0124         refreshAllUsers();
0125     }
0126     return QObject::event(event);
0127 }
0128 
0129 void UserListModel::userAdded(Quotient::User *user)
0130 {
0131     auto pos = findUserPos(user);
0132     beginInsertRows(QModelIndex(), pos, pos);
0133     m_users.insert(pos, user);
0134     endInsertRows();
0135     connect(user, &User::defaultAvatarChanged, this, [this, user]() {
0136         refreshUser(user, {AvatarRole});
0137     });
0138 }
0139 
0140 void UserListModel::userRemoved(Quotient::User *user)
0141 {
0142     auto pos = findUserPos(user);
0143     if (pos != m_users.size()) {
0144         beginRemoveRows(QModelIndex(), pos, pos);
0145         m_users.removeAt(pos);
0146         endRemoveRows();
0147         user->disconnect(this);
0148     } else {
0149         qWarning() << "Trying to remove a room member not in the user list";
0150     }
0151 }
0152 
0153 void UserListModel::refreshUser(Quotient::User *user, const QList<int> &roles)
0154 {
0155     auto pos = findUserPos(user);
0156     if (pos != m_users.size()) {
0157         Q_EMIT dataChanged(index(pos), index(pos), roles);
0158     } else {
0159         qWarning() << "Trying to access a room member not in the user list";
0160     }
0161 }
0162 
0163 void UserListModel::refreshAllUsers()
0164 {
0165     beginResetModel();
0166     for (User *user : std::as_const(m_users)) {
0167         user->disconnect(this);
0168     }
0169     m_users.clear();
0170 
0171     if (m_currentRoom != nullptr) {
0172         m_users = m_currentRoom->users();
0173         std::sort(m_users.begin(), m_users.end(), m_currentRoom->memberSorter());
0174 
0175         for (User *user : std::as_const(m_users)) {
0176             connect(user, &User::defaultAvatarChanged, this, [this, user]() {
0177                 refreshUser(user, {AvatarRole});
0178             });
0179         }
0180         connect(m_currentRoom->connection(), &Connection::loggedOut, this, [this]() {
0181             setRoom(nullptr);
0182         });
0183     }
0184     endResetModel();
0185     Q_EMIT usersRefreshed();
0186 }
0187 
0188 int UserListModel::findUserPos(Quotient::User *user) const
0189 {
0190     return findUserPos(m_currentRoom->safeMemberName(user->id()));
0191 }
0192 
0193 int UserListModel::findUserPos(const QString &username) const
0194 {
0195     if (!m_currentRoom) {
0196         return 0;
0197     }
0198     return m_currentRoom->memberSorter().lowerBoundIndex(m_users, username);
0199 }
0200 
0201 QHash<int, QByteArray> UserListModel::roleNames() const
0202 {
0203     QHash<int, QByteArray> roles;
0204 
0205     roles[DisplayNameRole] = "name";
0206     roles[UserIdRole] = "userId";
0207     roles[AvatarRole] = "avatar";
0208     roles[ObjectRole] = "user";
0209     roles[PowerLevelRole] = "powerLevel";
0210     roles[PowerLevelStringRole] = "powerLevelString";
0211 
0212     return roles;
0213 }
0214 
0215 #include "moc_userlistmodel.cpp"