Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(MessagesSystemGroup): collapse actor removed messages, collapse previously open groups with unread marker #11876

Merged
merged 3 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/components/MessagesList/MessagesGroup/Message/Message.vue
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,17 @@ export default {
type: Boolean,
default: undefined,
},
/**
* Specifies if the message is inside a collapsed group.
*/
isCollapsedSystemMessage: {
type: Boolean,
default: false,
},
lastCollapsedMessageId: {
type: [String, Number],
default: 0,
},
/**
* The type of the message.
*/
Expand Down Expand Up @@ -329,8 +340,17 @@ export default {
return !this.nextMessageId || this.id === this.conversation?.lastMessage?.id
},

visualLastLastReadMessageId() {
return this.$store.getters.getVisualLastReadMessageId(this.token)
},

isLastReadMessage() {
return !this.isLastMessage && this.id === this.$store.getters.getVisualLastReadMessageId(this.token)
if (this.isLastMessage) {
return false
}
return (!this.isCollapsedSystemMessage && this.id === this.visualLastLastReadMessageId)
|| (this.isCollapsedSystemMessage && this.id === this.visualLastLastReadMessageId && this.id !== this.lastCollapsedMessageId)
|| (this.isCombinedSystemMessage && this.lastCollapsedMessageId === this.visualLastLastReadMessageId)
},

isSystemMessage() {
Expand Down
29 changes: 20 additions & 9 deletions src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
:is-combined-system-message-collapsed="messagesCollapsed.collapsed"
:next-message-id="getNextMessageId(messagesCollapsed.messages.at(-1))"
:previous-message-id="getPrevMessageId(messagesCollapsed.messages.at(0))"
:last-collapsed-message-id="messagesCollapsed.lastId"
@toggle-combined-system-message="toggleCollapsed(messagesCollapsed)" />
</ul>
<ul v-show="messagesCollapsed.messages?.length === 1 || !messagesCollapsed.collapsed"
Expand All @@ -41,6 +42,8 @@
:key="message.id"
v-bind="message"
:token="token"
is-collapsed-system-message
:last-collapsed-message-id="messagesCollapsed.lastId"
:next-message-id="getNextMessageId(message)"
:previous-message-id="getPrevMessageId(message)" />
</ul>
Expand Down Expand Up @@ -153,6 +156,14 @@ export default {
return 'user_added'
}

// Group users removed by one actor
if (message1.systemMessage === 'user_removed'
&& message1.systemMessage === message2.systemMessage
&& message1.actorId === message2.actorId
&& message1.actorType === message2.actorType) {
return 'user_removed'
}

// Group users reconnected in a minute
if (message1.systemMessage === 'call_joined'
&& message2.systemMessage === 'call_left'
Expand Down Expand Up @@ -194,30 +205,30 @@ export default {
let lastMessage = null
let forceNextGroup = false
for (const message of messages) {
const isLastRead = message.id === this.lastReadMessageId
const groupingType = this.messagesShouldBeGrouped(message, lastMessage)
if (!groupingType || forceNextGroup) {
groups.push({ id: message.id, messages: [message], type: '', collapsed: this.groupIsCollapsed[message.id] ?? !isLastRead })
groups.push({ id: message.id, lastId: message.id, messages: [message], type: '', collapsed: this.groupIsCollapsed[message.id] ?? true })
forceNextGroup = false
} else {
if (groupingType === 'call_reconnected') {
groups.push({ id: message.id, messages: [groups.at(-1).messages.pop()], type: '', collapsed: this.groupIsCollapsed[message.id] ?? !isLastRead })
groups.push({ id: message.id, lastId: message.id, messages: [groups.at(-1).messages.pop()], type: '', collapsed: this.groupIsCollapsed[message.id] ?? true })
groups.at(-1).lastId = groups.at(-1).messages.at(-1).id
forceNextGroup = true
}
groups.at(-1).messages.push(message)
groups.at(-1).lastId = message.id
groups.at(-1).type = groupingType
if (isLastRead) {

// Check if last read message is hidden inside the collapsed group, and open it, if so.
// Otherwise, combined system message will show a marker
const isLastReadInsideGroup = this.lastReadMessageId >= groups.at(-1).id && this.lastReadMessageId < groups.at(-1).lastId
if (isLastReadInsideGroup) {
groups.at(-1).collapsed = false
}
}
lastMessage = message
}

groups.forEach(group => {
if (this.groupIsCollapsed[group.id] === undefined) {
this.groupIsCollapsed[group.id] = group.collapsed
}
})
return groups
},

Expand Down
4 changes: 2 additions & 2 deletions src/components/MessagesList/MessagesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -431,10 +431,10 @@ export default {
},

softUpdateAuthorGroups(oldGroups, newGroups, dateTimestamp) {
const oldKeys = Object.keys(oldGroups)
Object.entries(newGroups).forEach(([id, newGroup]) => {
if (!oldGroups[id]) {
const oldId = oldKeys.find(key => id < key && oldGroups[key].nextMessageId <= newGroup.nextMessageId)
const oldId = Object.keys(oldGroups)
.find(key => id < key && oldGroups[key].nextMessageId <= newGroup.nextMessageId)
if (oldId) {
// newGroup includes oldGroup and more old messages, remove oldGroup
delete this.messagesGroupedByDateByAuthor[dateTimestamp][oldId]
Expand Down
51 changes: 51 additions & 0 deletions src/composables/useCombinedSystemMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,57 @@ export function useCombinedSystemMessage() {
}
}

// Handle cases when actor removed users from conversation (when remove team/group, for example)
if (type === 'user_removed') {
messages.forEach(message => {
if (checkIfSelfIsOneOfUsers(message)) {
selfIsUser = true
} else {
combinedMessage.messageParameters[`user${referenceIndex}`] = message.messageParameters.user
referenceIndex++
}
usersCounter++
})

if (checkIfSelfIsActor(combinedMessage)) {
if (usersCounter === 2) {
combinedMessage.message = t('spreed', 'You removed {user0} and {user1}')
} else {
combinedMessage.message = n('spreed',
'You removed {user0}, {user1} and %n more participant',
'You removed {user0}, {user1} and %n more participants', usersCounter - 2)
}
} else if (selfIsUser) {
if (usersCounter === 2) {
combinedMessage.message = actorIsAdministrator
? t('spreed', 'An administrator removed you and {user0}')
: t('spreed', '{actor} removed you and {user0}')
} else {
combinedMessage.message = actorIsAdministrator
? n('spreed',
'An administrator removed you, {user0} and %n more participant',
'An administrator removed you, {user0} and %n more participants', usersCounter - 2)
: n('spreed',
'{actor} removed you, {user0} and %n more participant',
'{actor} removed you, {user0} and %n more participants', usersCounter - 2)
}
} else {
if (usersCounter === 2) {
combinedMessage.message = actorIsAdministrator
? t('spreed', 'An administrator removed {user0} and {user1}')
: t('spreed', '{actor} removed {user0} and {user1}')
} else {
combinedMessage.message = actorIsAdministrator
? n('spreed',
'An administrator removed {user0}, {user1} and %n more participant',
'An administrator removed {user0}, {user1} and %n more participants', usersCounter - 2)
: n('spreed',
'{actor} removed {user0}, {user1} and %n more participant',
'{actor} removed {user0}, {user1} and %n more participants', usersCounter - 2)
}
}
}

// Handle cases when users joined or left the call
if (type === 'call_joined' || type === 'call_left') {
const storedUniqueUsers = []
Expand Down
Loading