File indexing completed on 2025-02-16 04:48:28
0001 // SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "matrixroomsmodel.h" 0005 0006 #include <Quotient/room.h> 0007 0008 using namespace Quotient; 0009 0010 Q_DECLARE_METATYPE(Quotient::JoinState) 0011 0012 MatrixRoomsModel::MatrixRoomsModel(QObject *parent) 0013 : QAbstractListModel(parent) 0014 { 0015 } 0016 0017 void MatrixRoomsModel::setConnection(Connection *connection) 0018 { 0019 if (connection == m_connection) { 0020 return; 0021 } 0022 if (m_connection) { 0023 m_connection->disconnect(this); 0024 } 0025 if (!connection) { 0026 m_connection = nullptr; 0027 beginResetModel(); 0028 m_rooms.clear(); 0029 endResetModel(); 0030 return; 0031 } 0032 0033 m_connection = connection; 0034 0035 for (Room *room : std::as_const(m_rooms)) { 0036 room->disconnect(this); 0037 } 0038 0039 connect(connection, &Connection::connected, this, &MatrixRoomsModel::doResetModel); 0040 connect(connection, &Connection::invitedRoom, this, &MatrixRoomsModel::updateRoom); 0041 connect(connection, &Connection::joinedRoom, this, &MatrixRoomsModel::updateRoom); 0042 connect(connection, &Connection::leftRoom, this, &MatrixRoomsModel::updateRoom); 0043 connect(connection, &Connection::aboutToDeleteRoom, this, &MatrixRoomsModel::deleteRoom); 0044 connect(connection, &Connection::directChatsListChanged, this, [this, connection](Quotient::DirectChatsMap additions, Quotient::DirectChatsMap removals) { 0045 auto refreshRooms = [this, &connection](Quotient::DirectChatsMap rooms) { 0046 for (const QString &roomID : std::as_const(rooms)) { 0047 auto room = connection->room(roomID); 0048 if (room) { 0049 refresh(room); 0050 } 0051 } 0052 }; 0053 0054 refreshRooms(std::move(additions)); 0055 refreshRooms(std::move(removals)); 0056 }); 0057 0058 doResetModel(); 0059 0060 Q_EMIT connectionChanged(); 0061 } 0062 0063 void MatrixRoomsModel::doResetModel() 0064 { 0065 beginResetModel(); 0066 m_rooms.clear(); 0067 const auto rooms = m_connection->allRooms(); 0068 for (const auto &room : rooms) { 0069 doAddRoom(room); 0070 } 0071 endResetModel(); 0072 } 0073 0074 Room *MatrixRoomsModel::roomAt(int row) const 0075 { 0076 return m_rooms.at(row); 0077 } 0078 0079 void MatrixRoomsModel::doAddRoom(Room *room) 0080 { 0081 if (room) { 0082 if (!room->successorId().isEmpty()) { 0083 return; 0084 } 0085 m_rooms.append(room); 0086 connectRoomSignals(room); 0087 } else { 0088 Q_ASSERT(false); 0089 } 0090 } 0091 0092 void MatrixRoomsModel::connectRoomSignals(Room *room) 0093 { 0094 connect(room, &Room::displaynameChanged, this, [this, room] { 0095 refresh(room); 0096 }); 0097 connect(room, &Room::avatarChanged, this, [this, room] { 0098 refresh(room, {AvatarRole, AvatarImageRole}); 0099 }); 0100 } 0101 0102 void MatrixRoomsModel::updateRoom(Room *room, Room *prev) 0103 { 0104 if (prev == room) { 0105 refresh(room); 0106 return; 0107 } 0108 const auto newRoom = room; 0109 const auto it = std::find_if(m_rooms.begin(), m_rooms.end(), [=](const Room *r) { 0110 return r == prev || r == newRoom; 0111 }); 0112 if (it != m_rooms.end()) { 0113 const int row = it - m_rooms.begin(); 0114 // There's no guarantee that prev != newRoom 0115 if (*it == prev && *it != newRoom) { 0116 prev->disconnect(this); 0117 m_rooms.replace(row, newRoom); 0118 connectRoomSignals(newRoom); 0119 } 0120 Q_EMIT dataChanged(index(row), index(row)); 0121 } else { 0122 beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count()); 0123 doAddRoom(newRoom); 0124 endInsertRows(); 0125 } 0126 } 0127 0128 void MatrixRoomsModel::deleteRoom(Room *room) 0129 { 0130 const auto it = std::find(m_rooms.begin(), m_rooms.end(), room); 0131 if (it == m_rooms.end()) { 0132 return; 0133 } 0134 const int row = it - m_rooms.begin(); 0135 beginRemoveRows(QModelIndex(), row, row); 0136 m_rooms.erase(it); 0137 endRemoveRows(); 0138 } 0139 0140 int MatrixRoomsModel::rowCount(const QModelIndex &parent) const 0141 { 0142 if (parent.isValid()) { 0143 return 0; 0144 } 0145 return m_rooms.count(); 0146 } 0147 0148 QVariant MatrixRoomsModel::data(const QModelIndex &index, int role) const 0149 { 0150 if (!index.isValid()) { 0151 return {}; 0152 } 0153 0154 if (index.row() >= m_rooms.count()) { 0155 return {}; 0156 } 0157 Room *room = m_rooms.at(index.row()); 0158 switch (role) { 0159 case DisplayNameRole: 0160 return room->displayName(); 0161 case AvatarRole: 0162 return room->avatarMediaId(); 0163 case CanonicalAliasRole: 0164 return room->canonicalAlias(); 0165 case TopicRole: 0166 return room->topic(); 0167 case IdRole: 0168 return room->id(); 0169 case AvatarImageRole: 0170 return room->avatar(48); 0171 case CategoryRole: 0172 if (room->joinState() == JoinState::Invite) { 0173 return InvitedRoom; 0174 } 0175 if (room->isFavourite()) { 0176 return FavoriteRoom; 0177 } 0178 if (room->isLowPriority()) { 0179 return LowPriorityRoom; 0180 } 0181 if (room->isDirectChat()) { 0182 return DirectChatRoom; 0183 } 0184 if (const RoomCreateEvent *creationEvent = room->creation(); creationEvent) { 0185 const auto contentJson = creationEvent->contentJson(); 0186 if (contentJson.value(Quotient::TypeKey) == QLatin1StringView("m.space")) { 0187 return Space; 0188 } 0189 } 0190 return RegularRoom; 0191 } 0192 return {}; 0193 } 0194 0195 void MatrixRoomsModel::refresh(Room *room, const QVector<int> &roles) 0196 { 0197 const auto it = std::find(m_rooms.begin(), m_rooms.end(), room); 0198 if (it == m_rooms.end()) { 0199 return; 0200 } 0201 const auto idx = index(it - m_rooms.begin()); 0202 Q_EMIT dataChanged(idx, idx, roles); 0203 } 0204 0205 QHash<int, QByteArray> MatrixRoomsModel::roleNames() const 0206 { 0207 QHash<int, QByteArray> roles; 0208 roles[DisplayNameRole] = "displayName"; 0209 roles[AvatarRole] = "avatar"; 0210 roles[CanonicalAliasRole] = "canonicalAlias"; 0211 roles[TopicRole] = "topic"; 0212 roles[IdRole] = "id"; 0213 roles[AvatarImageRole] = "avatarImage"; 0214 roles[CategoryRole] = "category"; 0215 return roles; 0216 } 0217 0218 #include "moc_matrixroomsmodel.cpp"