Skip to content

Commit

Permalink
Merge pull request #11872 from nextcloud/chore/noid/refactor-chat-scr…
Browse files Browse the repository at this point in the history
…olling

chore: refactor scroll to bottom logic
  • Loading branch information
DorraJaouad authored Mar 22, 2024
2 parents 5a28d95 + 7cbc5d3 commit 35beec6
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/components/ChatView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export default {
},

smoothScrollToBottom() {
EventBus.$emit('smooth-scroll-chat-to-bottom')
EventBus.$emit('scroll-chat-to-bottom', { smooth: true, force: true })
},
},

Expand Down
7 changes: 0 additions & 7 deletions src/components/MessagesList/MessagesGroup/Message/Message.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ export default {

watch: {
showJoinCallButton() {
EventBus.$emit('scroll-chat-to-bottom')
EventBus.$emit('scroll-chat-to-bottom', { smooth: true })
},
},

Expand Down
103 changes: 33 additions & 70 deletions src/components/MessagesList/MessagesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -308,6 +307,9 @@ export default {
} else {
this.softUpdateByDateGroups(this.messagesGroupedByDateByAuthor, newGroups)
}

// scroll to bottom if needed
this.scrollToBottom({ smooth: true })
},
},
},
Expand All @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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',
})
})

},

/**
Expand Down
2 changes: 1 addition & 1 deletion src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion src/store/fileUploadStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down

0 comments on commit 35beec6

Please sign in to comment.