aboutsummaryrefslogtreecommitdiff
path: root/lib/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/room.cpp')
-rw-r--r--lib/room.cpp126
1 files changed, 68 insertions, 58 deletions
diff --git a/lib/room.cpp b/lib/room.cpp
index 439baeb5..fec2dc18 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -263,8 +263,11 @@ class Room::Private
QJsonObject toJson() const;
private:
+ using users_shortlist_t = std::array<User*, 3>;
+ template<typename ContT>
+ users_shortlist_t buildShortlist(const ContT& users) const;
+ users_shortlist_t buildShortlist(const QStringList& userIds) const;
QString calculateDisplayname() const;
- QString roomNameFromMemberNames(const QList<User*>& userlist) const;
bool isLocalUser(const User* u) const
{
@@ -985,9 +988,9 @@ bool Room::usesEncryption() const
int Room::joinedCount() const
{
- return d->summary.joinedMemberCount > 0
- ? d->summary.joinedMemberCount
- : d->membersMap.size();
+ return d->summary.joinedMemberCount.omitted()
+ ? d->membersMap.size()
+ : d->summary.joinedMemberCount.value();
}
int Room::invitedCount() const
@@ -1008,13 +1011,14 @@ GetRoomEventsJob* Room::eventsHistoryJob() const
Room::Changes Room::Private::setSummary(RoomSummary&& newSummary)
{
- if (summary == newSummary)
+ if (!summary.merge(newSummary))
return Change::NoChange;
summary = move(newSummary);
qCDebug(MAIN).nospace()
- << "Updated room summary: joined " << summary.joinedMemberCount
+ << "Updated room summary for" << q->objectName()
+ << ": joined " << summary.joinedMemberCount
<< ", invited " << summary.invitedMemberCount
- << ", heroes: " << summary.heroes.join(',');
+ << ", heroes: " << summary.heroes.value().join(',');
return Change::SummaryChange;
}
@@ -1391,7 +1395,7 @@ bool isEchoEvent(const RoomEventPtr& le, const PendingEventItem& re)
bool Room::supportsCalls() const
{
- return d->membersMap.size() == 2;
+ return joinedCount() == 2;
}
void Room::inviteCall(const QString& callId, const int lifetime,
@@ -2045,49 +2049,35 @@ Room::Changes Room::processAccountDataEvent(EventPtr&& event)
return Change::NoChange;
}
-QString Room::Private::roomNameFromMemberNames(const QList<User *> &userlist) const
+template <typename ContT>
+Room::Private::users_shortlist_t
+Room::Private::buildShortlist(const ContT& users) const
{
- // This is part 3(i,ii,iii) in the room displayname algorithm described
- // in the CS spec (see also Room::Private::updateDisplayname() ).
- // The spec requires to sort users lexicographically by state_key (user id)
- // and use disambiguated display names of two topmost users excluding
- // the current one to render the name of the room.
-
- // std::array is the leanest C++ container
- std::array<User*, 2> first_two = { {nullptr, nullptr} };
+ // To calculate room display name the spec requires to sort users
+ // lexicographically by state_key (user id) and use disambiguated
+ // display names of two topmost users excluding the current one to render
+ // the name of the room. The below code selects 3 topmost users,
+ // slightly extending the spec.
+ users_shortlist_t shortlist { }; // Prefill with nullptrs
std::partial_sort_copy(
- userlist.begin(), userlist.end(),
- first_two.begin(), first_two.end(),
- [this](const User* u1, const User* u2) {
- // Filter out the "me" user so that it never hits the room name
+ users.begin(), users.end(),
+ shortlist.begin(), shortlist.end(),
+ [this] (const User* u1, const User* u2) {
+ // localUser(), if it's in the list, is sorted below all others
return isLocalUser(u2) || (!isLocalUser(u1) && u1->id() < u2->id());
}
);
+ return shortlist;
+}
- // Spec extension. A single person in the chat but not the local user
- // (the local user is invited).
- if (userlist.size() == 1 && !isLocalUser(first_two.front()) &&
- joinState == JoinState::Invite)
- return tr("Invitation from %1")
- .arg(q->roomMembername(first_two.front()));
-
- // i. One-on-one chat. first_two[1] == localUser() in this case.
- if (userlist.size() == 2)
- return q->roomMembername(first_two[0]);
-
- // ii. Two users besides the current one.
- if (userlist.size() == 3)
- return tr("%1 and %2")
- .arg(q->roomMembername(first_two[0]),
- q->roomMembername(first_two[1]));
-
- // iii. More users.
- if (userlist.size() > 3)
- return tr("%1 and %Ln other(s)", "", userlist.size() - 3)
- .arg(q->roomMembername(first_two[0]));
-
- // userlist.size() < 2 - apparently, there's only current user in the room
- return QString();
+Room::Private::users_shortlist_t
+Room::Private::buildShortlist(const QStringList& userIds) const
+{
+ QList<User*> users;
+ users.reserve(userIds.size());
+ for (const auto& h: userIds)
+ users.push_back(q->user(h));
+ return buildShortlist(users);
}
QString Room::Private::calculateDisplayname() const
@@ -2110,22 +2100,42 @@ QString Room::Private::calculateDisplayname() const
//if (!q->aliases().empty() && !q->aliases().at(0).isEmpty())
// return q->aliases().at(0);
- // 3. Room members
- if (!summary.heroes.empty())
+ // Supplementary code for 3 and 4: build the shortlist of users whose names
+ // will be used to construct the room name. Takes into account MSC688's
+ // "heroes" if available.
+
+ const bool emptyRoom = membersMap.isEmpty() ||
+ (membersMap.size() == 1 && isLocalUser(*membersMap.begin()));
+ const auto shortlist =
+ !summary.heroes.omitted() ? buildShortlist(summary.heroes.value()) :
+ !emptyRoom ? buildShortlist(membersMap) :
+ buildShortlist(membersLeft);
+
+ QStringList names;
+ for (auto u: shortlist)
{
- QList<User*> users; users.reserve(summary.heroes.size());
- for (const auto& h: summary.heroes)
- users.push_back(q->user(h));
- dispName = roomNameFromMemberNames(users);
- } else
- dispName = roomNameFromMemberNames(membersMap.values());
- if (!dispName.isEmpty())
- return dispName;
+ if (u == nullptr || isLocalUser(u))
+ break;
+ names.push_back(q->roomMembername(u));
+ }
+
+ auto usersCountExceptLocal = emptyRoom
+ ? membersLeft.size() - int(joinState == JoinState::Leave)
+ : q->joinedCount() - int(joinState == JoinState::Join);
+ if (usersCountExceptLocal > int(shortlist.size()))
+ names <<
+ tr("%Ln other(s)",
+ "Used to make a room name from user names: A, B and _N others_",
+ usersCountExceptLocal);
+ auto namesList = QLocale().createSeparatedList(names);
+
+ // 3. Room members
+ if (!emptyRoom)
+ return namesList;
// 4. Users that previously left the room
- dispName = roomNameFromMemberNames(membersLeft);
- if (!dispName.isEmpty())
- return tr("Empty room (was: %1)").arg(dispName);
+ if (membersLeft.size() > 0)
+ return tr("Empty room (was: %1)").arg(namesList);
// 5. Fail miserably
return tr("Empty room (%1)").arg(id);