File indexing completed on 2024-05-05 05:01:24

0001 // SPDX-FileCopyrightText: 2019-2020 Black Hat <bhat@encom.eu.org>
0002 // SPDX-License-Identifier: GPL-3.0-only
0003 
0004 #include "publicroomlistmodel.h"
0005 
0006 #include <Quotient/connection.h>
0007 
0008 #include "publicroomlist_logging.h"
0009 
0010 using namespace Quotient;
0011 
0012 PublicRoomListModel::PublicRoomListModel(QObject *parent)
0013     : QAbstractListModel(parent)
0014 {
0015 }
0016 
0017 Quotient::Connection *PublicRoomListModel::connection() const
0018 {
0019     return m_connection;
0020 }
0021 
0022 void PublicRoomListModel::setConnection(Connection *conn)
0023 {
0024     if (m_connection == conn) {
0025         return;
0026     }
0027 
0028     beginResetModel();
0029 
0030     nextBatch = QString();
0031     attempted = false;
0032     rooms.clear();
0033     m_server.clear();
0034 
0035     if (m_connection) {
0036         m_connection->disconnect(this);
0037     }
0038 
0039     endResetModel();
0040 
0041     m_connection = conn;
0042 
0043     if (job) {
0044         job->abandon();
0045         job = nullptr;
0046         Q_EMIT searchingChanged();
0047     }
0048 
0049     if (m_connection) {
0050         next();
0051     }
0052 
0053     Q_EMIT connectionChanged();
0054     Q_EMIT serverChanged();
0055 }
0056 
0057 QString PublicRoomListModel::server() const
0058 {
0059     return m_server;
0060 }
0061 
0062 void PublicRoomListModel::setServer(const QString &value)
0063 {
0064     if (m_server == value) {
0065         return;
0066     }
0067 
0068     m_server = value;
0069 
0070     beginResetModel();
0071 
0072     nextBatch = QString();
0073     attempted = false;
0074     rooms.clear();
0075 
0076     endResetModel();
0077 
0078     if (job) {
0079         job->abandon();
0080         job = nullptr;
0081         Q_EMIT searchingChanged();
0082     }
0083 
0084     if (m_connection) {
0085         next();
0086     }
0087 
0088     Q_EMIT serverChanged();
0089 }
0090 
0091 QString PublicRoomListModel::searchText() const
0092 {
0093     return m_searchText;
0094 }
0095 
0096 void PublicRoomListModel::setSearchText(const QString &value)
0097 {
0098     if (m_searchText == value) {
0099         return;
0100     }
0101 
0102     m_searchText = value;
0103     Q_EMIT searchTextChanged();
0104 
0105     nextBatch = QString();
0106     attempted = false;
0107 
0108     if (job) {
0109         job->abandon();
0110         job = nullptr;
0111         Q_EMIT searchingChanged();
0112     }
0113 }
0114 
0115 bool PublicRoomListModel::showOnlySpaces() const
0116 {
0117     return m_showOnlySpaces;
0118 }
0119 
0120 void PublicRoomListModel::setShowOnlySpaces(bool showOnlySpaces)
0121 {
0122     if (showOnlySpaces == m_showOnlySpaces) {
0123         return;
0124     }
0125     m_showOnlySpaces = showOnlySpaces;
0126     Q_EMIT showOnlySpacesChanged();
0127 }
0128 
0129 void PublicRoomListModel::search(int limit)
0130 {
0131     if (limit < 1 || attempted) {
0132         return;
0133     }
0134 
0135     if (job) {
0136         qCDebug(PublicRoomList) << "Other job running, ignore";
0137         return;
0138     }
0139 
0140     next(limit);
0141 }
0142 
0143 void PublicRoomListModel::next(int limit)
0144 {
0145     if (m_connection == nullptr || limit < 1) {
0146         return;
0147     }
0148 
0149     if (job) {
0150         qCDebug(PublicRoomList) << "Other job running, ignore";
0151         return;
0152     }
0153 
0154     QStringList roomTypes;
0155     if (m_showOnlySpaces) {
0156         roomTypes += QLatin1String("m.space");
0157     }
0158     job = m_connection->callApi<QueryPublicRoomsJob>(m_server, limit, nextBatch, QueryPublicRoomsJob::Filter{m_searchText, roomTypes});
0159     Q_EMIT searchingChanged();
0160 
0161     connect(job, &BaseJob::finished, this, [this] {
0162         if (!attempted) {
0163             beginResetModel();
0164             rooms.clear();
0165             endResetModel();
0166 
0167             attempted = true;
0168         }
0169 
0170         if (job->status() == BaseJob::Success) {
0171             nextBatch = job->nextBatch();
0172 
0173             this->beginInsertRows({}, rooms.count(), rooms.count() + job->chunk().count() - 1);
0174             rooms.append(job->chunk());
0175             this->endInsertRows();
0176         }
0177 
0178         this->job = nullptr;
0179         Q_EMIT searchingChanged();
0180     });
0181 }
0182 
0183 QVariant PublicRoomListModel::data(const QModelIndex &index, int role) const
0184 {
0185     if (!index.isValid()) {
0186         return QVariant();
0187     }
0188 
0189     if (index.row() >= rooms.count()) {
0190         qCDebug(PublicRoomList) << "something's wrong: index.row() >= rooms.count()";
0191         return {};
0192     }
0193     auto room = rooms.at(index.row());
0194     if (role == DisplayNameRole) {
0195         auto displayName = room.name;
0196         if (!displayName.isEmpty()) {
0197             return displayName;
0198         }
0199 
0200         displayName = room.canonicalAlias;
0201         if (!displayName.isEmpty()) {
0202             return displayName;
0203         }
0204 
0205         if (!displayName.isEmpty()) {
0206             return displayName;
0207         }
0208 
0209         return room.roomId;
0210     }
0211     if (role == AvatarUrlRole) {
0212         auto avatarUrl = room.avatarUrl;
0213         if (avatarUrl.isEmpty() || !m_connection) {
0214             return QUrl();
0215         }
0216         return m_connection->makeMediaUrl(avatarUrl);
0217     }
0218     if (role == TopicRole) {
0219         return room.topic;
0220     }
0221     if (role == RoomIdRole) {
0222         return room.roomId;
0223     }
0224     if (role == AliasRole) {
0225         if (!room.canonicalAlias.isEmpty()) {
0226             return room.canonicalAlias;
0227         }
0228         return {};
0229     }
0230     if (role == MemberCountRole) {
0231         return room.numJoinedMembers;
0232     }
0233     if (role == AllowGuestsRole) {
0234         return room.guestCanJoin;
0235     }
0236     if (role == WorldReadableRole) {
0237         return room.worldReadable;
0238     }
0239     if (role == IsJoinedRole) {
0240         if (!m_connection) {
0241             return {};
0242         }
0243 
0244         return m_connection->room(room.roomId, JoinState::Join) != nullptr;
0245     }
0246 
0247     return {};
0248 }
0249 
0250 QHash<int, QByteArray> PublicRoomListModel::roleNames() const
0251 {
0252     QHash<int, QByteArray> roles;
0253 
0254     roles[DisplayNameRole] = "displayName";
0255     roles[AvatarUrlRole] = "avatarUrl";
0256     roles[TopicRole] = "topic";
0257     roles[RoomIdRole] = "roomId";
0258     roles[MemberCountRole] = "memberCount";
0259     roles[AllowGuestsRole] = "allowGuests";
0260     roles[WorldReadableRole] = "worldReadable";
0261     roles[IsJoinedRole] = "isJoined";
0262     roles[AliasRole] = "alias";
0263 
0264     return roles;
0265 }
0266 
0267 int PublicRoomListModel::rowCount(const QModelIndex &parent) const
0268 {
0269     if (parent.isValid()) {
0270         return 0;
0271     }
0272 
0273     return rooms.count();
0274 }
0275 
0276 bool PublicRoomListModel::canFetchMore(const QModelIndex &parent) const
0277 {
0278     Q_UNUSED(parent)
0279     return !nextBatch.isEmpty();
0280 }
0281 
0282 void PublicRoomListModel::fetchMore(const QModelIndex &parent)
0283 {
0284     Q_UNUSED(parent)
0285     next();
0286 }
0287 
0288 bool PublicRoomListModel::searching() const
0289 {
0290     return job != nullptr;
0291 }
0292 
0293 #include "moc_publicroomlistmodel.cpp"