diff --git a/Quotient/connection.cpp b/Quotient/connection.cpp index 80704e2dd..88aa3b9d9 100644 --- a/Quotient/connection.cpp +++ b/Quotient/connection.cpp @@ -576,6 +576,9 @@ void Connection::Private::consumeAccountData(Events&& accountDataEvents) remove_if(directChatUsers, [&remoteRemovals](auto it) { return remoteRemovals.contains(it.value(), it.key()); }); + remove_if(directChatMemberIds, [&remoteRemovals, this](auto it) { + return remoteRemovals.contains(q->user(it.value()), it.key()); + }); // Remove from dcLocalRemovals what the server already has. remove_if(dcLocalRemovals, [&remoteRemovals](auto it) { return remoteRemovals.contains(it.key(), it.value()); @@ -597,6 +600,7 @@ void Connection::Private::consumeAccountData(Events&& accountDataEvents) remoteAdditions.insert(u, it.value()); directChats.insert(u, it.value()); directChatUsers.insert(it.value(), u); + directChatMemberIds.insert(it.value(), it.key()); qCDebug(MAIN) << "Marked room" << it.value() << "as a direct chat with" << u->id(); } @@ -905,6 +909,7 @@ void Connection::doInDirectChat(User* u, d->directChats.remove(it.key(), it.value()); d->directChatUsers.remove(it.value(), const_cast(it.key())); // FIXME + d->directChatMemberIds.remove(it.value(), it.key()->id()); } emit directChatsListChanged({}, removals); } @@ -1265,6 +1270,7 @@ void Connection::addToDirectChats(const Room* room, const QString& userId) return; Q_ASSERT(!d->directChatUsers.contains(room->id(), u)); d->directChats.insert(u, room->id()); + d->directChatMemberIds.insert(room->id(), userId); d->directChatUsers.insert(room->id(), u); d->dcLocalAdditions.insert(u, room->id()); emit directChatsListChanged({ { u, room->id() } }, {}); @@ -1277,11 +1283,36 @@ void Connection::addToDirectChats(const Room* room, User* user) return; Q_ASSERT(!d->directChatUsers.contains(room->id(), user)); d->directChats.insert(user, room->id()); + d->directChatMemberIds.insert(room->id(), user->id()); d->directChatUsers.insert(room->id(), user); d->dcLocalAdditions.insert(user, room->id()); emit directChatsListChanged({ { user, room->id() } }, {}); } +void Connection::removeFromDirectChats(const QString& roomId, const QString& userId) +{ + Q_ASSERT(!roomId.isEmpty()); + const auto u = user(userId); + if ((!userId.isEmpty() && !d->directChats.contains(u, roomId)) + || d->directChats.key(roomId) == nullptr) + return; + + DirectChatsMap removals; + if (u != nullptr) { + d->directChats.remove(u, roomId); + d->directChatUsers.remove(roomId, u); + d->directChatMemberIds.remove(roomId, u->id()); + removals.insert(u, roomId); + d->dcLocalRemovals.insert(u, roomId); + } else { + removals = remove_if(d->directChats, + [&roomId](auto it) { return it.value() == roomId; }); + d->directChatUsers.remove(roomId); + d->dcLocalRemovals += removals; + } + emit directChatsListChanged({}, removals); +} + void Connection::removeFromDirectChats(const QString& roomId, User* user) { Q_ASSERT(!roomId.isEmpty()); @@ -1293,6 +1324,7 @@ void Connection::removeFromDirectChats(const QString& roomId, User* user) if (user != nullptr) { d->directChats.remove(user, roomId); d->directChatUsers.remove(roomId, user); + d->directChatMemberIds.remove(roomId, user->id()); removals.insert(user, roomId); d->dcLocalRemovals.insert(user, roomId); } else { @@ -1306,7 +1338,13 @@ void Connection::removeFromDirectChats(const QString& roomId, User* user) bool Connection::isDirectChat(const QString& roomId) const { - return d->directChatUsers.contains(roomId); + return d->directChatMemberIds.contains(roomId); +} + +QList Connection::directChatMemberIds(const Room* room) const +{ + Q_ASSERT(room != nullptr); + return d->directChatMemberIds.values(room->id()); } QList Connection::directChatUsers(const Room* room) const @@ -1438,7 +1476,7 @@ void Connection::setEncryptionDefault(bool useByDefault) Private::encryptionDefault = useByDefault; } #endif -dialog + void Connection::setRoomFactory(room_factory_t f) { _roomFactory = std::move(f); diff --git a/Quotient/connection.h b/Quotient/connection.h index 51d4677d0..3016744f3 100644 --- a/Quotient/connection.h +++ b/Quotient/connection.h @@ -233,6 +233,17 @@ class QUOTIENT_API Connection : public QObject { //! \sa directChatsListChanged void addToDirectChats(const Room* room, User* user); + //! \brief Unmark the room from direct chats + //! + //! This function removes the room id from direct chats either for + //! a specific \p user or for all users if \p userId is empty. + //! The room id is used to allow removal of, e.g., ids of forgotten + //! rooms; a Room object need not exist. Emits the signal + //! immediately, without waiting to complete synchronisation with + //! the server. + //! \sa directChatsListChanged + void removeFromDirectChats(const QString& roomId, const QString& userId = {}); + //! \brief Unmark the room from direct chats //! //! This function removes the room id from direct chats either for @@ -250,6 +261,12 @@ class QUOTIENT_API Connection : public QObject { //! Get the whole map from users to direct chat rooms DirectChatsMap directChats() const; + //! \brief Retrieve the list of member IDs the room is a direct chat with + //! + //! \return The list of member IDs for which this room is marked as + //! a direct chat; an empty list if the room is not a direct chat + QList directChatMemberIds(const Room* room) const; + //! \brief Retrieve the list of users the room is a direct chat with //! \return The list of users for which this room is marked as //! a direct chat; an empty list if the room is not a direct chat diff --git a/Quotient/connection_p.h b/Quotient/connection_p.h index a7ebc116a..1b842da1e 100644 --- a/Quotient/connection_p.h +++ b/Quotient/connection_p.h @@ -46,6 +46,7 @@ class Q_DECL_HIDDEN Quotient::Connection::Private { QVector pendingStateRoomIds; QMap userMap; DirectChatsMap directChats; + QMultiHash directChatMemberIds; DirectChatUsersMap directChatUsers; // The below two variables track local changes between sync completions. // See https://github.com/quotient-im/libQuotient/wiki/Handling-direct-chat-events diff --git a/Quotient/room.cpp b/Quotient/room.cpp index 45179baf2..d59fb812a 100644 --- a/Quotient/room.cpp +++ b/Quotient/room.cpp @@ -1463,6 +1463,18 @@ bool Room::isServerNoticeRoom() const bool Room::isDirectChat() const { return connection()->isDirectChat(id()); } +QList Room::directChatMembers() const +{ + auto memberIds = connection()->directChatMemberIds(this); + QList members; + for (const auto& memberId : memberIds) { + if (currentState().contains(memberId)) { + members.append(RoomMember(this, currentState().get(memberId))); + } + } + return members; +} + QList Room::directChatUsers() const { return connection()->directChatUsers(this); diff --git a/Quotient/room.h b/Quotient/room.h index f8b1047e6..e7e8a7ba2 100644 --- a/Quotient/room.h +++ b/Quotient/room.h @@ -721,6 +721,9 @@ class QUOTIENT_API Room : public QObject { /// Check whether this room is a direct chat Q_INVOKABLE bool isDirectChat() const; + /// Get the list of members this room is a direct chat with + QList directChatMembers() const; + /// Get the list of users this room is a direct chat with QList directChatUsers() const;