diff --git a/src/components/ChatView.vue b/src/components/ChatView.vue index e7dc23c6b53..1549b669dd1 100644 --- a/src/components/ChatView.vue +++ b/src/components/ChatView.vue @@ -224,7 +224,7 @@ export default { }, smoothScrollToBottom() { - EventBus.$emit('smooth-scroll-chat-to-bottom') + EventBus.$emit('scroll-chat-to-bottom', { smooth: true, force: true }) }, }, diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue index 079a9ec4bcb..4da5892f01a 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.vue +++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue @@ -450,13 +450,6 @@ export default { }, }, - watch: { - // Scroll list to the bottom if reaction to the message was added, as it expands the list - reactions() { - EventBus.$emit('scroll-chat-to-bottom-if-sticky') - }, - }, - methods: { lastReadMessageVisibilityChanged(isVisible) { if (isVisible) { diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue index 30dc957a848..24ca3a11a82 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue @@ -365,7 +365,7 @@ export default { watch: { showJoinCallButton() { - EventBus.$emit('scroll-chat-to-bottom') + EventBus.$emit('scroll-chat-to-bottom', { smooth: true }) }, }, diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index 58c9778cd0f..1ee91fdc4e6 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -279,7 +279,6 @@ export default { if (oldValue) { this.$store.dispatch('cancelLookForNewMessages', { requestId: oldValue }) } - this.$emit('update:is-chat-scrolled-to-bottom', true) this.handleStartGettingMessagesPreconditions() // Remove expired messages when joining a room @@ -308,6 +307,9 @@ export default { } else { this.softUpdateByDateGroups(this.messagesGroupedByDateByAuthor, newGroups) } + + // scroll to bottom if needed + this.scrollToBottom({ smooth: true }) }, }, }, @@ -316,10 +318,7 @@ export default { this.debounceUpdateReadMarkerPosition = debounce(this.updateReadMarkerPosition, 1000) this.debounceHandleScroll = debounce(this.handleScroll, 50) - this.scrollToBottom() - EventBus.$on('scroll-chat-to-bottom', this.handleScrollChatToBottomEvent) - EventBus.$on('smooth-scroll-chat-to-bottom', this.smoothScrollToBottom) - EventBus.$on('scroll-chat-to-bottom-if-sticky', this.scrollToBottomIfSticky) + EventBus.$on('scroll-chat-to-bottom', this.scrollToBottom) EventBus.$on('focus-message', this.focusMessage) EventBus.$on('route-change', this.onRouteChange) subscribe('networkOffline', this.handleNetworkOffline) @@ -339,9 +338,7 @@ export default { this.debounceHandleScroll.clear?.() window.removeEventListener('focus', this.onWindowFocus) - EventBus.$off('scroll-chat-to-bottom', this.handleScrollChatToBottomEvent) - EventBus.$off('smooth-scroll-chat-to-bottom', this.smoothScrollToBottom) - EventBus.$on('scroll-chat-to-bottom-if-sticky', this.scrollToBottomIfSticky) + EventBus.$off('scroll-chat-to-bottom', this.scrollToBottom) EventBus.$off('focus-message', this.focusMessage) EventBus.$off('route-change', this.onRouteChange) @@ -638,7 +635,7 @@ export default { if (!isFocused) { // if no anchor was present or the message to focus on did not exist, // scroll to bottom - this.scrollToBottom() + this.scrollToBottom({ force: true }) } // if no scrollbars, clear read marker directly as scrolling is not possible for the user to clear it @@ -752,10 +749,7 @@ export default { return } - const followInNewMessages = this.conversation.lastMessage - && this.conversation.lastReadMessage === this.conversation.lastMessage.id - - await this.getNewMessages(followInNewMessages) + await this.getNewMessages() }, async getMessageContext(messageId) { @@ -815,13 +809,11 @@ export default { /** * Creates a long polling request for a new message. * - * @param {boolean} scrollToBottom Whether we should try to automatically scroll to the bottom */ - async getNewMessages(scrollToBottom = true) { + async getNewMessages() { if (this.destroying) { return } - // Make the request try { // TODO: move polling logic to the store and also cancel timers on cancel @@ -831,11 +823,6 @@ export default { lastKnownMessageId: this.$store.getters.getLastKnownMessageId(this.token), requestId: this.chatIdentifier, }) - - // Scroll to the last message if sticky - if (scrollToBottom && this.isSticky) { - this.smoothScrollToBottom() - } } catch (exception) { if (Axios.isCancel(exception)) { console.debug('The request has been canceled', exception) @@ -1106,66 +1093,42 @@ export default { }, /** - * @param {object} options Event options - * @param {boolean} options.force Set to true, if the chat should be scrolled to the bottom even when it was not before - */ - handleScrollChatToBottomEvent(options) { - if ((options && options.force) || this.isChatScrolledToBottom) { - this.scrollToBottom() - } - }, - - /** - * Scrolls to the bottom of the list (to show reaction to the last message). - */ - scrollToBottomIfSticky() { - if (this.isSticky) { - this.scrollToBottom() - } - }, - - /** - * Scrolls to the bottom of the list smoothly. + * Scrolls to the bottom of the list. + * @param {object} options Options for scrolling + * @param {boolean} [options.smooth] 'smooth' scrolling to the bottom ('auto' by default) + * @param {boolean} [options.force] force scrolling to the bottom (otherwise check for current position) */ - smoothScrollToBottom() { + scrollToBottom(options = {}) { this.$nextTick(() => { if (!this.$refs.scroller) { return } - if (this.isWindowVisible && (document.hasFocus() || this.isInCall)) { - // scrollTo is used when the user is watching - this.$refs.scroller.scrollTo({ - top: this.$refs.scroller.scrollHeight, - behavior: 'smooth', - }) + let newTop + if (options?.force) { + newTop = this.$refs.scroller.scrollHeight this.setChatScrolledToBottom(true) - } else { - // Otherwise we jump half a message and stop autoscrolling, so the user can read up - if (this.$refs.scroller.scrollHeight - this.$refs.scroller.scrollTop - this.$refs.scroller.offsetHeight < 40) { - // Single new line from the previous author is 35px so scroll half a line - this.$refs.scroller.scrollTop += 10 - } else { - // Single new line from the new author is 75px so scroll half an avatar - this.$refs.scroller.scrollTop += 40 - } - this.setChatScrolledToBottom(false) - } - }) - }, - /** - * Scrolls to the bottom of the list. - */ - scrollToBottom() { - this.$nextTick(() => { - if (!this.$refs.scroller) { + } else if (!this.isSticky) { + // Reading old messages return + } else if (!this.isWindowVisible) { + const firstUnreadMessageHeight = this.$refs.scroller.scrollHeight - this.$refs.scroller.scrollTop - this.$refs.scroller.offsetHeight + const scrollBy = firstUnreadMessageHeight < 40 ? 10 : 40 + // We jump half a message and stop autoscrolling, so the user can read up + // Single new line from the previous author is 35px so scroll half a line (10px) + // Single new line from the new author is 75px so scroll half an avatar (40px) + newTop = this.$refs.scroller.scrollTop + scrollBy + this.setChatScrolledToBottom(false) + } else { + newTop = this.$refs.scroller.scrollHeight + this.setChatScrolledToBottom(true) } - this.$refs.scroller.scrollTop = this.$refs.scroller.scrollHeight - this.setChatScrolledToBottom(true) + this.$refs.scroller.scrollTo({ + top: newTop, + behavior: options?.smooth ? 'smooth' : 'auto', + }) }) - }, /** diff --git a/src/components/NewMessage/NewMessage.vue b/src/components/NewMessage/NewMessage.vue index 15092792a81..1beb135211f 100644 --- a/src/components/NewMessage/NewMessage.vue +++ b/src/components/NewMessage/NewMessage.vue @@ -695,7 +695,7 @@ export default { this.text = '' this.userData = {} // Scrolls the message list to the last added message - EventBus.$emit('smooth-scroll-chat-to-bottom') + EventBus.$emit('scroll-chat-to-bottom', { smooth: true, force: true }) // Also remove the message to be replied for this conversation this.chatExtrasStore.removeParentIdToReply(this.token) diff --git a/src/store/fileUploadStore.js b/src/store/fileUploadStore.js index eac5f68c072..67827d3d11f 100644 --- a/src/store/fileUploadStore.js +++ b/src/store/fileUploadStore.js @@ -323,7 +323,7 @@ const actions = { // Add temporary messages (files) to the messages list dispatch('addTemporaryMessage', { token, message }) // Scroll the message list - EventBus.$emit('scroll-chat-to-bottom', { force: true }) + EventBus.$emit('scroll-chat-to-bottom', { smooth: true, force: true }) } await dispatch('prepareUploadPaths', { token, uploadId })