Merge remote-tracking branch 'upstream/feat/custom-virtual-scrolling' into shigusegubu
* upstream/feat/custom-virtual-scrolling: whoops fix data property being called the wrong name in conversation fix warnings and console errors fix minor bugs make virtual scrolling optional in case people want to be able to ctrl-f all page rename hidden stuff to virtualHidden, remove log add custom solution for virtual scrolling to ease ram and cpu use when scrolling for a long time
This commit is contained in:
commit
0f743af271
11 changed files with 101 additions and 17 deletions
|
@ -35,7 +35,9 @@ const conversation = {
|
|||
data () {
|
||||
return {
|
||||
highlight: null,
|
||||
expanded: false
|
||||
expanded: false,
|
||||
// Approximate minimum height of a status, gets overwritten with real one
|
||||
virtualHeight: '120px'
|
||||
}
|
||||
},
|
||||
props: [
|
||||
|
@ -44,7 +46,8 @@ const conversation = {
|
|||
'isPage',
|
||||
'pinnedStatusIdsObject',
|
||||
'inProfile',
|
||||
'profileUserId'
|
||||
'profileUserId',
|
||||
'virtualHidden'
|
||||
],
|
||||
created () {
|
||||
if (this.isPage) {
|
||||
|
@ -102,6 +105,9 @@ const conversation = {
|
|||
},
|
||||
isExpanded () {
|
||||
return this.expanded || this.isPage
|
||||
},
|
||||
hiddenStyle () {
|
||||
return this.virtualHidden ? { height: this.virtualHeight } : {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
@ -121,6 +127,9 @@ const conversation = {
|
|||
if (value) {
|
||||
this.fetchConversation()
|
||||
}
|
||||
},
|
||||
virtualHidden (value) {
|
||||
this.virtualHeight = `${this.$el.clientHeight}px`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<template>
|
||||
<div
|
||||
:style="hiddenStyle"
|
||||
class="timeline panel-default"
|
||||
:class="[isExpanded ? 'panel' : 'panel-disabled']"
|
||||
>
|
||||
<div
|
||||
v-if="isExpanded"
|
||||
v-if="isExpanded && !virtualHidden"
|
||||
class="panel-heading conversation-heading"
|
||||
>
|
||||
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
||||
|
@ -28,6 +29,7 @@
|
|||
:replies="getReplies(status.id)"
|
||||
:in-profile="inProfile"
|
||||
:profile-user-id="profileUserId"
|
||||
:virtual-hidden="virtualHidden"
|
||||
class="status-fadein panel-body"
|
||||
@goto="setHighlight"
|
||||
@toggleExpanded="toggleExpanded"
|
||||
|
|
|
@ -76,9 +76,9 @@
|
|||
<li>
|
||||
<Checkbox v-model="useStreamingApi">
|
||||
{{ $t('settings.useStreamingApi') }}
|
||||
<br/>
|
||||
<br>
|
||||
<small>
|
||||
{{ $t('settings.useStreamingApiWarning') }}
|
||||
{{ $t('settings.useStreamingApiWarning') }}
|
||||
</small>
|
||||
</Checkbox>
|
||||
</li>
|
||||
|
@ -92,6 +92,11 @@
|
|||
{{ $t('settings.reply_link_preview') }}
|
||||
</Checkbox>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="virtualScrolling">
|
||||
{{ $t('settings.virtual_scrolling') }}
|
||||
</Checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ const Status = {
|
|||
'inlineExpanded',
|
||||
'showPinned',
|
||||
'inProfile',
|
||||
'profileUserId'
|
||||
'profileUserId',
|
||||
'virtualHidden'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
|
@ -121,7 +122,7 @@ const Status = {
|
|||
return this.mergedConfig.hideFilteredStatuses
|
||||
},
|
||||
hideStatus () {
|
||||
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses)
|
||||
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses) || this.virtualHidden
|
||||
},
|
||||
isFocused () {
|
||||
// retweet or root of an expanded conversation
|
||||
|
|
|
@ -18,14 +18,16 @@ const StillImage = {
|
|||
},
|
||||
methods: {
|
||||
onLoad () {
|
||||
this.imageLoadHandler && this.imageLoadHandler(this.$refs.src)
|
||||
const image = this.$refs.src
|
||||
if (!image) return
|
||||
this.imageLoadHandler && this.imageLoadHandler(image)
|
||||
const canvas = this.$refs.canvas
|
||||
if (!canvas) return
|
||||
const width = this.$refs.src.naturalWidth
|
||||
const height = this.$refs.src.naturalHeight
|
||||
const width = image.naturalWidth
|
||||
const height = image.naturalHeight
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
canvas.getContext('2d').drawImage(this.$refs.src, 0, 0, width, height)
|
||||
canvas.getContext('2d').drawImage(image, 0, 0, width, height)
|
||||
},
|
||||
onError () {
|
||||
this.imageLoadError && this.imageLoadError()
|
||||
|
|
|
@ -32,7 +32,8 @@ const Timeline = {
|
|||
return {
|
||||
paused: false,
|
||||
unfocused: false,
|
||||
bottomedOut: false
|
||||
bottomedOut: false,
|
||||
virtualScrollIndex: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -68,6 +69,16 @@ const Timeline = {
|
|||
},
|
||||
pinnedStatusIdsObject () {
|
||||
return keyBy(this.pinnedStatusIds)
|
||||
},
|
||||
statusesToDisplay () {
|
||||
const amount = this.timeline.visibleStatuses.length
|
||||
const statusesPerSide = Math.ceil(Math.max(10, window.innerHeight / 100))
|
||||
const min = Math.max(0, this.virtualScrollIndex - statusesPerSide)
|
||||
const max = Math.min(amount, this.virtualScrollIndex + statusesPerSide)
|
||||
return this.timeline.visibleStatuses.slice(min, max).map(_ => _.id)
|
||||
},
|
||||
virtualScrollingEnabled () {
|
||||
return this.$store.getters.mergedConfig.virtualScrolling
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
@ -79,7 +90,7 @@ const Timeline = {
|
|||
const credentials = store.state.users.currentUser.credentials
|
||||
const showImmediately = this.timeline.visibleStatuses.length === 0
|
||||
|
||||
window.addEventListener('scroll', this.scrollLoad)
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
|
||||
if (store.state.api.fetchers[this.timelineName]) { return false }
|
||||
|
||||
|
@ -100,7 +111,7 @@ const Timeline = {
|
|||
window.addEventListener('keydown', this.handleShortKey)
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('scroll', this.scrollLoad)
|
||||
window.removeEventListener('scroll', this.handleScroll)
|
||||
window.removeEventListener('keydown', this.handleShortKey)
|
||||
if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false)
|
||||
this.$store.commit('setLoading', { timeline: this.timelineName, value: false })
|
||||
|
@ -142,6 +153,48 @@ const Timeline = {
|
|||
}
|
||||
})
|
||||
}, 1000, this),
|
||||
determineVisibleStatuses () {
|
||||
if (!this.$refs.timeline) return
|
||||
|
||||
const statuses = this.$refs.timeline.children
|
||||
|
||||
if (statuses.length === 0) return
|
||||
|
||||
const bodyBRect = document.body.getBoundingClientRect()
|
||||
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
|
||||
|
||||
const centerOfScreen = window.pageYOffset + (window.innerHeight * 0.5)
|
||||
|
||||
// Start from approximating the index of some visible status by using the
|
||||
// the center of the screen on the timeline.
|
||||
let approxIndex = Math.floor(statuses.length * (centerOfScreen / height))
|
||||
let err = statuses[approxIndex].getBoundingClientRect().y
|
||||
|
||||
// if we have a previous scroll index that can be used, test if it's
|
||||
// closer than the previous approximation, use it if so
|
||||
if (
|
||||
this.virtualScrollIndex < statuses.length &&
|
||||
Math.abs(err) > statuses[this.virtualScrollIndex].getBoundingClientRect().y
|
||||
) {
|
||||
approxIndex = this.virtualScrollIndex
|
||||
err = statuses[approxIndex].getBoundingClientRect().y
|
||||
}
|
||||
|
||||
// if the status is too far from viewport, check the next/previous ones if
|
||||
// they happen to be better
|
||||
while (err < -100 && approxIndex < statuses.length - 1) {
|
||||
approxIndex++
|
||||
err = statuses[approxIndex].getBoundingClientRect().y
|
||||
}
|
||||
while (err > window.innerHeight + 100 && approxIndex > 0) {
|
||||
approxIndex--
|
||||
err = statuses[approxIndex].getBoundingClientRect().y
|
||||
}
|
||||
|
||||
// this status is now the center point for virtual scrolling and visible
|
||||
// statuses will be nearby statuses before and after it
|
||||
this.virtualScrollIndex = approxIndex
|
||||
},
|
||||
scrollLoad (e) {
|
||||
const bodyBRect = document.body.getBoundingClientRect()
|
||||
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
|
||||
|
@ -152,6 +205,10 @@ const Timeline = {
|
|||
this.fetchOlderStatuses()
|
||||
}
|
||||
},
|
||||
handleScroll: throttle(function (e) {
|
||||
this.determineVisibleStatuses()
|
||||
this.scrollLoad(e)
|
||||
}, 100),
|
||||
handleVisibilityChange () {
|
||||
this.unfocused = document.hidden
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div :class="classes.body">
|
||||
<div class="timeline">
|
||||
<div
|
||||
ref="timeline"
|
||||
class="timeline"
|
||||
>
|
||||
<template v-for="statusId in pinnedStatusIds">
|
||||
<conversation
|
||||
v-if="timeline.statusesObject[statusId]"
|
||||
|
@ -56,6 +59,7 @@
|
|||
:collapsable="true"
|
||||
:in-profile="inProfile"
|
||||
:profile-user-id="userId"
|
||||
:virtual-hidden="virtualScrollingEnabled && !statusesToDisplay.includes(status.id)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -384,6 +384,7 @@
|
|||
"false": "no",
|
||||
"true": "yes"
|
||||
},
|
||||
"virtual_scrolling": "Optimize timeline rendering",
|
||||
"fun": "Fun",
|
||||
"greentext": "Meme arrows",
|
||||
"notifications": "Notifications",
|
||||
|
|
|
@ -228,7 +228,8 @@
|
|||
"values": {
|
||||
"false": "pois päältä",
|
||||
"true": "päällä"
|
||||
}
|
||||
},
|
||||
"virtual_scrolling": "Optimoi aikajanan suorituskykyä"
|
||||
},
|
||||
"time": {
|
||||
"day": "{0} päivä",
|
||||
|
|
|
@ -49,7 +49,8 @@ export const defaultState = {
|
|||
useContainFit: false,
|
||||
greentext: undefined, // instance default
|
||||
hidePostStats: undefined, // instance default
|
||||
hideUserStats: undefined // instance default
|
||||
hideUserStats: undefined, // instance default
|
||||
virtualScrolling: undefined // instance default
|
||||
}
|
||||
|
||||
// caching the instance default properties
|
||||
|
|
|
@ -34,6 +34,7 @@ const defaultState = {
|
|||
showFeaturesPanel: true,
|
||||
minimalScopesMode: false,
|
||||
greentext: false,
|
||||
virtualScrolling: true,
|
||||
|
||||
// Nasty stuff
|
||||
pleromaBackend: true,
|
||||
|
|
Loading…
Add table
Reference in a new issue