File indexing completed on 2024-05-12 16:25:07

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