From 58b2e3c320a20e01e1035e331ff8a80a18a451e3 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Wed, 20 Mar 2024 14:24:42 +0100 Subject: [PATCH 1/3] feat(MessagesSystemGroup): group user removed by one actor Signed-off-by: Maksim Sukharev --- .../MessagesGroup/MessagesSystemGroup.vue | 8 +++ src/composables/useCombinedSystemMessage.js | 51 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue index 46d23ac6100..28b1bafd0b5 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue +++ b/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue @@ -153,6 +153,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' diff --git a/src/composables/useCombinedSystemMessage.js b/src/composables/useCombinedSystemMessage.js index a37640c86bc..c9810a86b7c 100644 --- a/src/composables/useCombinedSystemMessage.js +++ b/src/composables/useCombinedSystemMessage.js @@ -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 = [] From 15380b780c6930230307e8288ed59fbcc23f1d19 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Wed, 20 Mar 2024 14:54:28 +0100 Subject: [PATCH 2/3] fix(MessagesList): cycle through only existing group keys when soft updating Signed-off-by: Maksim Sukharev --- src/components/MessagesList/MessagesList.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index 58c9778cd0f..e83128c4c75 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -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] From 1f822036acf1bc3dcb2760ef03745e538f2240a1 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 21 Mar 2024 12:32:46 +0100 Subject: [PATCH 3/3] fix(MessagesSystemGroup): collapse groups, if they don't contain unread messages Signed-off-by: Maksim Sukharev --- .../MessagesGroup/Message/Message.vue | 22 ++++++++++++++++++- .../MessagesGroup/MessagesSystemGroup.vue | 21 ++++++++++-------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue index 079a9ec4bcb..b7d49c175fc 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.vue +++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue @@ -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. */ @@ -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() { diff --git a/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue index 28b1bafd0b5..01dbd38b20a 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue +++ b/src/components/MessagesList/MessagesGroup/MessagesSystemGroup.vue @@ -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)" />
@@ -202,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 },