aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2018-08-11 19:06:20 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2018-08-11 19:06:20 +0900
commitb3559aa9ac082abe96da2bae084d0645b93fb658 (patch)
treee46f11654c5dbeddf0a68a23b1e34d93d0133f77
parent082f233dc9f429d06548fba90c8129ef3f83a4b4 (diff)
downloadlibquotient-b3559aa9ac082abe96da2bae084d0645b93fb658.tar.gz
libquotient-b3559aa9ac082abe96da2bae084d0645b93fb658.zip
Reverse direct chats map
Speeds up lookup of user(s) in a direct chat room. Also: "The other one's" avatar is used to set the avatar of direct chats only, not any room with 2 participants.
-rw-r--r--lib/connection.cpp37
-rw-r--r--lib/connection.h15
-rw-r--r--lib/room.cpp17
-rw-r--r--lib/room.h2
-rw-r--r--lib/user.cpp4
-rw-r--r--lib/user.h4
6 files changed, 47 insertions, 32 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index fcd73d04..29c044f1 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -89,6 +89,7 @@ class Connection::Private
QVector<Room*> firstTimeRooms;
QMap<QString, User*> userMap;
DirectChatsMap directChats;
+ DirectChatUsersMap directChatUsers;
std::unordered_map<QString, EventPtr> accountData;
QString userId;
@@ -356,6 +357,9 @@ void Connection::onSyncSuccess(SyncData &&data) {
erase_if(d->directChats, [&usersToDCs] (auto it) {
return !usersToDCs.contains(it.key()->id(), it.value());
});
+ erase_if(d->directChatUsers, [&usersToDCs] (auto it) {
+ return !usersToDCs.contains(it.value()->id(), it.key());
+ });
if (MAIN().isDebugEnabled())
for (auto it = removals.begin(); it != removals.end(); ++it)
qCDebug(MAIN) << it.value()
@@ -364,12 +368,14 @@ void Connection::onSyncSuccess(SyncData &&data) {
DirectChatsMap additions;
for (auto it = usersToDCs.begin(); it != usersToDCs.end(); ++it)
{
- if (const auto* u = user(it.key()))
+ if (auto* u = user(it.key()))
{
if (!d->directChats.contains(u, it.value()))
{
+ Q_ASSERT(!d->directChatUsers.contains(it.value(), u));
additions.insert(u, it.value());
d->directChats.insert(u, it.value());
+ d->directChatUsers.insert(it.value(), u);
qCDebug(MAIN) << "Marked room" << it.value()
<< "as a direct chat with" << u->id();
}
@@ -520,7 +526,7 @@ CreateRoomJob* Connection::createRoom(RoomVisibility visibility,
void Connection::requestDirectChat(const QString& userId)
{
- if (const auto* u = user(userId))
+ if (auto* u = user(userId))
requestDirectChat(u);
else
qCCritical(MAIN)
@@ -528,7 +534,7 @@ void Connection::requestDirectChat(const QString& userId)
<< userId;
}
-void Connection::requestDirectChat(const User* u)
+void Connection::requestDirectChat(User* u)
{
doInDirectChat(u, [this] (Room* r) { emit directChatAvailable(r); });
}
@@ -536,7 +542,7 @@ void Connection::requestDirectChat(const User* u)
void Connection::doInDirectChat(const QString& userId,
const std::function<void(Room*)>& operation)
{
- if (const auto* u = user(userId))
+ if (auto* u = user(userId))
doInDirectChat(u, operation);
else
qCCritical(MAIN)
@@ -544,7 +550,7 @@ void Connection::doInDirectChat(const QString& userId,
<< userId;
}
-void Connection::doInDirectChat(const User* u,
+void Connection::doInDirectChat(User* u,
const std::function<void(Room*)>& operation)
{
Q_ASSERT(u);
@@ -591,7 +597,10 @@ void Connection::doInDirectChat(const User* u,
if (!removals.isEmpty())
{
for (auto it = removals.cbegin(); it != removals.cend(); ++it)
+ {
d->directChats.remove(it.key(), it.value());
+ d->directChatUsers.remove(it.value(), it.key());
+ }
d->broadcastDirectChatUpdates({}, removals);
}
@@ -871,17 +880,19 @@ void Connection::Private::broadcastDirectChatUpdates(const DirectChatsMap& addit
emit q->directChatsListChanged(additions, removals);
}
-void Connection::addToDirectChats(const Room* room, const User* user)
+void Connection::addToDirectChats(const Room* room, User* user)
{
Q_ASSERT(room != nullptr && user != nullptr);
if (d->directChats.contains(user, room->id()))
return;
+ Q_ASSERT(!d->directChatUsers.contains(room->id(), user));
d->directChats.insert(user, room->id());
+ d->directChatUsers.insert(room->id(), user);
DirectChatsMap additions { { user, room->id() } };
d->broadcastDirectChatUpdates(additions, {});
}
-void Connection::removeFromDirectChats(const QString& roomId, const User* user)
+void Connection::removeFromDirectChats(const QString& roomId, User* user)
{
Q_ASSERT(!roomId.isEmpty());
if ((user != nullptr && !d->directChats.contains(user, roomId)) ||
@@ -893,22 +904,24 @@ void Connection::removeFromDirectChats(const QString& roomId, const User* user)
{
removals.insert(user, roomId);
d->directChats.remove(user, roomId);
- }
- else
+ d->directChatUsers.remove(roomId, user);
+ } else {
removals = erase_if(d->directChats,
[&roomId] (auto it) { return it.value() == roomId; });
+ d->directChatUsers.remove(roomId);
+ }
d->broadcastDirectChatUpdates({}, removals);
}
bool Connection::isDirectChat(const QString& roomId) const
{
- return d->directChats.key(roomId) != nullptr;
+ return d->directChatUsers.contains(roomId);
}
-QList<const User*> Connection::directChatUsers(const Room* room) const
+QList<User*> Connection::directChatUsers(const Room* room) const
{
Q_ASSERT(room != nullptr);
- return d->directChats.keys(room->id());
+ return d->directChatUsers.values(room->id());
}
bool Connection::isIgnored(const User* user) const
diff --git a/lib/connection.h b/lib/connection.h
index e761acfd..9b253711 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -94,7 +94,12 @@ namespace QMatrixClient
using user_factory_t =
std::function<User*(Connection*, const QString&)>;
+ // Room ids, rather than room pointers, are used in the direct chat
+ // map types because the library keeps Invite rooms separate from
+ // rooms in Join and Leave state; and direct chats in account data
+ // are stored with no regard to their state.
using DirectChatsMap = QMultiHash<const User*, QString>;
+ using DirectChatUsersMap = QMultiHash<QString, User*>;
using IgnoredUsersList = IgnoredUsersEvent::content_type;
using UsersToDevicesToEvents =
@@ -171,7 +176,7 @@ namespace QMatrixClient
*
* \sa directChatsListChanged
*/
- void addToDirectChats(const Room* room, const User* user);
+ void addToDirectChats(const Room* room, User* user);
/** Unmark the room from direct chats
* This function removes the room id from direct chats either for
@@ -184,7 +189,7 @@ namespace QMatrixClient
* \sa directChatsListChanged
*/
void removeFromDirectChats(const QString& roomId,
- const User* user = nullptr);
+ User* user = nullptr);
/** Check whether the room id corresponds to a direct chat */
bool isDirectChat(const QString& roomId) const;
@@ -196,7 +201,7 @@ namespace QMatrixClient
* @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
*/
- QList<const User*> directChatUsers(const Room* room) const;
+ QList<User*> directChatUsers(const Room* room) const;
/** Check whether a particular user is in the ignore list */
bool isIgnored(const User* user) const;
@@ -392,7 +397,7 @@ namespace QMatrixClient
*
* \sa directChatAvailable
*/
- void requestDirectChat(const User* u);
+ void requestDirectChat(User* u);
/** Run an operation in a direct chat with the user
* This method may return synchronously or asynchoronously depending
@@ -409,7 +414,7 @@ namespace QMatrixClient
* already. Instead of emitting a signal it executes the passed
* function object with the direct chat room as its parameter.
*/
- void doInDirectChat(const User* u,
+ void doInDirectChat(User* u,
const std::function<void(Room*)>& operation);
/** Create a direct chat with a single user, optional name and topic
diff --git a/lib/room.cpp b/lib/room.cpp
index 27f54ddb..91fb6831 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -332,15 +332,12 @@ QImage Room::avatar(int width, int height)
return d->avatar.get(connection(), width, height,
[=] { emit avatarChanged(); });
- // Use the other side's avatar for 1:1's
- if (d->membersMap.size() == 2)
- {
- auto theOtherOneIt = d->membersMap.begin();
- if (theOtherOneIt.value() == localUser())
- ++theOtherOneIt;
- return (*theOtherOneIt)->avatar(width, height, this,
- [=] { emit avatarChanged(); });
- }
+ // Use the first (excluding self) user's avatar for direct chats
+ const auto dcUsers = directChatUsers();
+ for (auto* u: dcUsers)
+ if (u != localUser())
+ return u->avatar(width, height, this, [=] { emit avatarChanged(); });
+
return {};
}
@@ -760,7 +757,7 @@ bool Room::isDirectChat() const
return connection()->isDirectChat(id());
}
-QList<const User*> Room::directChatUsers() const
+QList<User*> Room::directChatUsers() const
{
return connection()->directChatUsers(this);
}
diff --git a/lib/room.h b/lib/room.h
index 35263eaf..8e56c37a 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -285,7 +285,7 @@ namespace QMatrixClient
Q_INVOKABLE bool isDirectChat() const;
/** Get the list of users this room is a direct chat with */
- QList<const User*> directChatUsers() const;
+ QList<User*> directChatUsers() const;
Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId);
Q_INVOKABLE QUrl urlToDownload(const QString& eventId);
diff --git a/lib/user.cpp b/lib/user.cpp
index 12977b8a..b9f493c5 100644
--- a/lib/user.cpp
+++ b/lib/user.cpp
@@ -299,7 +299,7 @@ bool User::setAvatar(QIODevice* source)
std::bind(&Private::setAvatarOnServer, d.data(), _1, this));
}
-void User::requestDirectChat() const
+void User::requestDirectChat()
{
connection()->requestDirectChat(this);
}
@@ -356,7 +356,7 @@ QImage User::avatar(int width, int height, const Room* room)
}
QImage User::avatar(int width, int height, const Room* room,
- Avatar::get_callback_t callback)
+ const Avatar::get_callback_t& callback)
{
return avatarObject(room).get(d->connection, width, height,
[=] { emit avatarChanged(this, room); callback(); });
diff --git a/lib/user.h b/lib/user.h
index c33ed028..17f5625f 100644
--- a/lib/user.h
+++ b/lib/user.h
@@ -100,7 +100,7 @@ namespace QMatrixClient
Q_INVOKABLE QImage avatar(int requestedWidth, int requestedHeight,
const Room* room = nullptr);
QImage avatar(int width, int height, const Room* room,
- Avatar::get_callback_t callback);
+ const Avatar::get_callback_t& callback);
QString avatarMediaId(const Room* room = nullptr) const;
QUrl avatarUrl(const Room* room = nullptr) const;
@@ -120,7 +120,7 @@ namespace QMatrixClient
* The resulting chat is returned asynchronously via
* Connection::directChatAvailable()
*/
- void requestDirectChat() const;
+ void requestDirectChat();
/** Add the user to the ignore list */
void ignore();
/** Remove the user from the ignore list */