Limit the maximum number of avatars shown

Limit the maximum number of avatars shown for other user read markers and collapsed state events

For state events \
![image](/uploads/0d3ec7c3da02a8832dfdb18dc265db92/image.png)

For read markers \
![image](/uploads/5694f14927e5c10b2159e58445c8a0a3/image.png)
This commit is contained in:
James Graham
2023-05-12 15:54:15 +00:00
parent 023c51ac62
commit 88fada89ea
7 changed files with 130 additions and 8 deletions

View File

@@ -24,6 +24,8 @@ QVariant CollapseStateProxyModel::data(const QModelIndex &index, int role) const
return stateEventsList(mapToSource(index).row());
} else if (role == AuthorListRole) {
return authorList(mapToSource(index).row());
} else if (role == ExcessAuthorsRole) {
return excessAuthors(mapToSource(index).row());
}
return sourceModel()->data(mapToSource(index), role);
}
@@ -34,6 +36,7 @@ QHash<int, QByteArray> CollapseStateProxyModel::roleNames() const
roles[AggregateDisplayRole] = "aggregateDisplay";
roles[StateEventsRole] = "stateEvents";
roles[AuthorListRole] = "authorList";
roles[ExcessAuthorsRole] = "excessAuthors";
return roles;
}
@@ -130,5 +133,39 @@ QVariantList CollapseStateProxyModel::authorList(int sourceRow) const
break;
}
}
if (uniqueAuthors.count() > 5) {
uniqueAuthors = uniqueAuthors.mid(0, 5);
}
return uniqueAuthors;
}
QString CollapseStateProxyModel::excessAuthors(int row) const
{
QVariantList uniqueAuthors;
for (int i = row; i >= 0; i--) {
QVariant nextAvatar = sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole);
if (!uniqueAuthors.contains(nextAvatar)) {
uniqueAuthors.append(nextAvatar);
}
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
!= MessageEventModel::DelegateType::State // If it's not a state event
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
) {
break;
}
}
int excessAuthors;
if (uniqueAuthors.count() > 5) {
excessAuthors = uniqueAuthors.count() - 5;
} else {
excessAuthors = 0;
}
QString excessAuthorsString;
if (excessAuthors == 0) {
return QString();
} else {
return QStringLiteral("+ %1").arg(excessAuthors);
}
}

View File

@@ -25,7 +25,8 @@ public:
enum Roles {
AggregateDisplayRole = MessageEventModel::LastRole + 1, /**< Single line aggregation of all the state events. */
StateEventsRole, /**< List of state events in the aggregated state. */
AuthorListRole, /**< List of unique authors of the aggregated state event. */
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
};
/**
@@ -67,7 +68,12 @@ private:
[[nodiscard]] QVariantList stateEventsList(int row) const;
/**
* @brief List of unique authors for the aggregate state events starting at row.
* @brief List of the first 5 unique authors for the aggregate state events starting at row.
*/
[[nodiscard]] QVariantList authorList(int row) const;
/**
* @brief The number of unique authors beyond the first 5 for the aggregate state events starting at row.
*/
[[nodiscard]] QString excessAuthors(int row) const;
};

View File

@@ -57,6 +57,7 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
roles[ShowAuthorRole] = "showAuthor";
roles[ShowSectionRole] = "showSection";
roles[ReadMarkersRole] = "readMarkers";
roles[ExcessReadMarkersRole] = "excessReadMarkers";
roles[ReadMarkersStringRole] = "readMarkersString";
roles[ShowReadMarkersRole] = "showReadMarkers";
roles[ReactionRole] = "reaction";
@@ -248,7 +249,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
connect(m_currentRoom, &Room::changed, this, [this]() {
for (auto it = m_currentRoom->messageEvents().rbegin(); it != m_currentRoom->messageEvents().rend(); ++it) {
auto event = it->event();
refreshEventRoles(event->id(), {ReadMarkersRole, ReadMarkersStringRole});
refreshEventRoles(event->id(), {ReadMarkersRole, ReadMarkersStringRole, ExcessReadMarkersRole});
}
});
connect(m_currentRoom, &Room::newFileTransfer, this, &MessageEventModel::refreshEvent);
@@ -852,8 +853,13 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (role == ReadMarkersRole) {
#ifdef QUOTIENT_07
auto userIds = room()->userIdsAtEvent(evt.id());
userIds.remove(m_currentRoom->localUser()->id());
auto userIds_temp = room()->userIdsAtEvent(evt.id());
userIds_temp.remove(m_currentRoom->localUser()->id());
auto userIds = userIds_temp.values();
if (userIds.count() > 5) {
userIds = userIds.mid(0, 5);
}
#else
auto userIds = room()->usersAtEventId(evt.id());
userIds.removeAll(m_currentRoom->localUser());
@@ -873,6 +879,22 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return users;
}
if (role == ExcessReadMarkersRole) {
#ifdef QUOTIENT_07
auto userIds = room()->userIdsAtEvent(evt.id());
userIds.remove(m_currentRoom->localUser()->id());
#else
auto userIds = room()->usersAtEventId(evt.id());
userIds.removeAll(m_currentRoom->localUser());
#endif
if (userIds.count() > 5) {
return QStringLiteral("+ ") + QString::number(userIds.count() - 5);
} else {
return QString();
}
}
if (role == ReadMarkersStringRole) {
#ifdef QUOTIENT_07
auto userIds = room()->userIdsAtEvent(evt.id());

View File

@@ -86,7 +86,8 @@ public:
ShowAuthorRole, /**< Whether the author's name should be shown. */
ShowSectionRole, /**< Whether the section header should be shown. */
ReadMarkersRole, /**< Other users at the event for read marker tracking. */
ReadMarkersRole, /**< The first 5 other users at the event for read marker tracking. */
ExcessReadMarkersRole, /**< The number of other users at the event after the first 5. */
ReadMarkersStringRole, /**< String with the display name and mxID of the users at the event. */
ShowReadMarkersRole, /**< Whether there are any other user read markers to be shown. */
ReactionRole, /**< List of reactions to this event. */

View File

@@ -12,19 +12,46 @@ Flow {
property var avatarSize: Kirigami.Units.iconSizes.small
property alias model: avatarFlowRepeater.model
property string toolTipText
property alias excessAvatars: excessAvatarsLabel.text
spacing: -avatarSize / 2
Repeater {
id: avatarFlowRepeater
delegate: Kirigami.Avatar {
topInset: Kirigami.Units.smallSpacing / 2
topPadding: Kirigami.Units.smallSpacing / 2
implicitWidth: avatarSize
implicitHeight: avatarSize
implicitHeight: avatarSize + Kirigami.Units.smallSpacing / 2
name: modelData.displayName
source: modelData.avatarSource
color: modelData.color
}
}
QQC2.Label {
id: excessAvatarsLabel
visible: text !== ""
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
radius: height / 2
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
height: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing
width: Math.max(excessAvatarsTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
TextMetrics {
id: excessAvatarsTextMetrics
text: excessAvatarsLabel.text
}
}
QQC2.ToolTip.text: toolTipText
QQC2.ToolTip.visible: hoverHandler.hovered

View File

@@ -78,14 +78,41 @@ QQC2.Control {
Repeater {
model: authorList
delegate: Kirigami.Avatar {
topInset: Kirigami.Units.smallSpacing / 2
topPadding: Kirigami.Units.smallSpacing / 2
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing / 2
name: modelData.displayName
source: modelData.avatarSource
color: modelData.color
}
}
QQC2.Label {
id: excessAuthorsLabel
text: model.excessAuthors
visible: model.excessAuthors !== ""
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
radius: height / 2
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
}
height: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing
width: Math.max(excessAuthorsTextMetrics.advanceWidth + Kirigami.Units.smallSpacing * 2, height)
TextMetrics {
id: excessAuthorsTextMetrics
text: excessAuthorsLabel.text
}
}
}
QQC2.Label {
Layout.fillWidth: true
@@ -140,6 +167,7 @@ QQC2.Control {
visible: showReadMarkers
model: readMarkers
toolTipText: readMarkersString
excessAvatars: excessReadMarkers
}
}
}

View File

@@ -342,6 +342,7 @@ ColumnLayout {
visible: showReadMarkers
model: readMarkers
toolTipText: readMarkersString
excessAvatars: excessReadMarkers
}
function isVisibleInTimeline() {