Fixes for "scroll to latest"

This commit is contained in:
N-Pex 2025-06-19 10:47:16 +02:00
parent e3f7f1758f
commit f0382afd83
2 changed files with 54 additions and 35 deletions

View file

@ -369,10 +369,16 @@ body {
position: absolute; position: absolute;
bottom: 102px; bottom: 102px;
right: 16px; right: 16px;
opacity: 1;
transition: opacity 0.3s linear;
&.reversed { &.reversed {
top: 120px; top: 120px;
transform: rotate(180deg); transform: rotate(180deg);
} }
&.hidden {
pointer-events: none;
opacity: 0;
}
} }
.op-button { .op-button {

View file

@ -120,7 +120,7 @@
</div> </div>
<!-- "Scroll to end"-button --> <!-- "Scroll to end"-button -->
<v-btn v-if="!useVoiceMode" icon="arrow_downward" :class="{'scroll-to-end': true, 'reversed': reverseOrder}" v-show="showScrollToEnd" theme="dark" size="x-small" elevation="0" color="black" <v-btn v-if="!useVoiceMode" icon="arrow_downward" :class="{'scroll-to-end': true, 'reversed': reverseOrder, 'hidden': !showScrollToEnd}" theme="dark" size="x-small" elevation="0" color="black"
@click.stop="scrollToEndOfTimeline"> @click.stop="scrollToEndOfTimeline">
</v-btn> </v-btn>
@ -410,6 +410,7 @@ export default {
timelineWindowPaginating: false, timelineWindowPaginating: false,
scrollPosition: null, scrollPosition: null,
scrollUpdateTimer: null,
uploadBatch: undefined, uploadBatch: undefined,
showEmojiPicker: false, showEmojiPicker: false,
selectedEvent: null, selectedEvent: null,
@ -1210,13 +1211,7 @@ export default {
this.handleScrolledToLatest(false); this.handleScrolledToLatest(false);
} }
} }
this.delayedUpdateOfScrollToBottom();
this.showScrollToEnd =
container.scrollHeight === container.clientHeight
? false
: (this.reverseOrder ? (container.scrollTop.toFixed(0) > 0) : (container.scrollHeight - container.scrollTop.toFixed(0) > container.clientHeight)) ||
(this.timelineWindow && this.timelineWindow.canPaginate(EventTimeline.FORWARDS));
this.restartRRTimer(); this.restartRRTimer();
}, },
@ -1284,6 +1279,24 @@ export default {
} }
}, },
delayedUpdateOfScrollToBottom() {
if (this.scrollUpdateTimer) {
clearTimeout(this.scrollUpdateTimer);
}
this.scrollUpdateTimer = setTimeout(() => {
this.scrollUpdateTimer = null;
const container = this.chatContainer;
if (!container) {
return;
}
this.showScrollToEnd =
container.scrollHeight === container.clientHeight
? false
: (this.reverseOrder ? (container.scrollTop.toFixed(0) > 0) : (container.scrollHeight - container.scrollTop.toFixed(0) > container.clientHeight)) ||
(this.timelineWindow && this.timelineWindow.canPaginate(EventTimeline.FORWARDS));
}, 1000);
},
onEvent(event) { onEvent(event) {
//console.log("OnEvent", JSON.stringify(event)); //console.log("OnEvent", JSON.stringify(event));
if (event.getRoomId() !== this.roomId) { if (event.getRoomId() !== this.roomId) {
@ -1307,16 +1320,7 @@ export default {
if (loadingDone && event.forwardLooking && (!event.isRelation() || event.isMxThread || event.threadRootId || event.parentThread)) { if (loadingDone && event.forwardLooking && (!event.isRelation() || event.isMxThread || event.threadRootId || event.parentThread)) {
// If we are at bottom, scroll to see new events... // If we are at bottom, scroll to see new events...
var scrollToSeeNew = !event.isRedaction() && event.getSender() == this.$matrix.currentUserId; // When we sent, scroll var scrollToSeeNew = !event.isRedaction() && event.getSender() == this.$matrix.currentUserId; // When we sent, scroll
const container = this.chatContainer; this.handleScrolledToLatest(scrollToSeeNew || !this.showScrollToEnd);
if (container) {
if (this.reverseOrder && container.scrollTop.toFixed(0) == 0) {
scrollToSeeNew = true;
}
else if (!this.reverseOrder && container.scrollHeight - container.scrollTop.toFixed(0) == container.clientHeight) {
scrollToSeeNew = true;
}
}
this.handleScrolledToLatest(scrollToSeeNew);
// If kick or ban event, redirect to "goodbye"... // If kick or ban event, redirect to "goodbye"...
if (event.getType() === "m.room.member" && if (event.getType() === "m.room.member" &&
@ -1516,32 +1520,41 @@ export default {
}, },
smoothScrollToLatest() { smoothScrollToLatest() {
this.$nextTick(function () { this.$nextTick(() => {
// TODO - fix this. We need to wait until the "lastChild" below has been
// laid out correctly. If we do it "too early" it will have zero height and
// thus not correctly scrolled into the viewport. So we wait a few ticks...
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
const container = this.chatContainer; const container = this.chatContainer;
if (container && container.children.length > 0) { if (container && container.children.length > 0) {
if (this.reverseOrder) { if (this.reverseOrder) {
const firstChild = container.children[0]; const firstChild = container.children[0];
console.log("Scroll into view", firstChild); window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => { firstChild.scrollIntoView({
firstChild.scrollIntoView({ behavior: "smooth",
behavior: "smooth", block: "end",
block: "end", inline: "nearest",
inline: "nearest", });
}); });
});
} else { } else {
const lastChild = container.children[container.children.length - 1]; const lastChild = container.children[container.children.length - 1];
console.log("Scroll into view", lastChild); window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => { lastChild.scrollIntoView({
lastChild.scrollIntoView({ behavior: "smooth",
behavior: "smooth", block: "start",
block: "start", inline: "nearest",
inline: "nearest", });
}); });
}); }
} }
}
}); });
})
})
})
})
}, },
showMoreMessageOperations(e) { showMoreMessageOperations(e) {