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

chore: refactor scroll to bottom logic #11872

Merged
merged 5 commits into from
Mar 22, 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
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 })
DorraJaouad marked this conversation as resolved.
Show resolved Hide resolved
// 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
Loading