Improve scroller performance

pull/162/head
Varun Patil 2022-10-29 15:50:14 -07:00
parent 21276219a1
commit 0fbd076a52
8 changed files with 117 additions and 42 deletions

View File

@ -24,6 +24,7 @@ jobs:
- name: Build vue app - name: Build vue app
run: | run: |
make dev-setup make dev-setup
make patch-external
make build-js-production make build-js-production
zip -r vue.zip js/ zip -r vue.zip js/
@ -40,8 +41,8 @@ jobs:
# do not stop on another job's failure # do not stop on another job's failure
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['7.4'] php-versions: ["7.4"]
server-versions: ['stable25'] server-versions: ["stable25"]
services: services:
mysql: mysql:
@ -100,7 +101,6 @@ jobs:
name: report-mysql-${{ matrix.php-versions }}-${{ matrix.server-versions }} name: report-mysql-${{ matrix.php-versions }}-${{ matrix.server-versions }}
path: apps/${{ env.APP_NAME }}/playwright-report path: apps/${{ env.APP_NAME }}/playwright-report
pgsql: pgsql:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: vue needs: vue
@ -109,8 +109,8 @@ jobs:
# do not stop on another job's failure # do not stop on another job's failure
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['7.4'] php-versions: ["7.4"]
server-versions: ['stable25'] server-versions: ["stable25"]
services: services:
postgres: postgres:
@ -181,8 +181,8 @@ jobs:
# do not stop on another job's failure # do not stop on another job's failure
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: ['7.4'] php-versions: ["7.4"]
server-versions: ['stable25'] server-versions: ["stable25"]
steps: steps:
- name: Checkout server - name: Checkout server
@ -231,4 +231,3 @@ jobs:
with: with:
name: report-sqlite-${{ matrix.php-versions }}-${{ matrix.server-versions }} name: report-sqlite-${{ matrix.php-versions }}-${{ matrix.server-versions }}
path: apps/${{ env.APP_NAME }}/playwright-report path: apps/${{ env.APP_NAME }}/playwright-report

View File

@ -13,34 +13,35 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18.x node-version: 18.x
- name: Build - name: Build
run: | run: |
make dev-setup make dev-setup
make build-js-production make patch-external
./scripts/bundle.sh make build-js-production
./scripts/bundle.sh
- name: Upload app tarball to release - name: Upload app tarball to release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
id: attach_to_release id: attach_to_release
with: with:
file: memories.tar.gz file: memories.tar.gz
asset_name: memories.tar.gz asset_name: memories.tar.gz
tag: ${{ github.ref }} tag: ${{ github.ref }}
overwrite: true overwrite: true
- name: Upload app to Nextcloud appstore - name: Upload app to Nextcloud appstore
uses: R0Wi/nextcloud-appstore-push-action@v1 uses: R0Wi/nextcloud-appstore-push-action@v1
with: with:
app_name: ${{ env.APP_NAME }} app_name: ${{ env.APP_NAME }}
appstore_token: ${{ secrets.APPSTORE_TOKEN }} appstore_token: ${{ secrets.APPSTORE_TOKEN }}
download_url: ${{ steps.attach_to_release.outputs.browser_download_url }} download_url: ${{ steps.attach_to_release.outputs.browser_download_url }}
app_private_key: ${{ secrets.APP_PRIVATE_KEY }} app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
nightly: ${{ github.event.release.prerelease }} nightly: ${{ github.event.release.prerelease }}

View File

@ -26,6 +26,9 @@ build-js:
build-js-production: build-js-production:
rm -f js/* && npm run build rm -f js/* && npm run build
patch-external:
patch -p1 < patches/scroller.patch
watch-js: watch-js:
npm run watch npm run watch

2
package-lock.json generated
View File

@ -23,7 +23,7 @@
"vue-material-design-icons": "^5.1.2", "vue-material-design-icons": "^5.1.2",
"vue-property-decorator": "^9.1.2", "vue-property-decorator": "^9.1.2",
"vue-router": "^3.5.4", "vue-router": "^3.5.4",
"vue-virtual-scroller": "^1.1.2", "vue-virtual-scroller": "1.1.2",
"webdav": "^4.11.0" "webdav": "^4.11.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -43,7 +43,7 @@
"vue-material-design-icons": "^5.1.2", "vue-material-design-icons": "^5.1.2",
"vue-property-decorator": "^9.1.2", "vue-property-decorator": "^9.1.2",
"vue-router": "^3.5.4", "vue-router": "^3.5.4",
"vue-virtual-scroller": "^1.1.2", "vue-virtual-scroller": "1.1.2",
"webdav": "^4.11.0" "webdav": "^4.11.0"
}, },
"browserslist": [ "browserslist": [

View File

@ -0,0 +1,54 @@
--- ./node_modules/vue-virtual-scroller/dist/vue-virtual-scroller.esm.js 2022-10-29 15:40:12.517184534 -0700
+++ ./node_modules/vue-virtual-scroller/dist/vue-virtual-scroller.esm.js 2022-10-29 15:40:42.814432774 -0700
@@ -99,6 +99,10 @@
type: Boolean,
default: false
},
+ updateInterval: {
+ type: Number,
+ default: 0,
+ },
skipHover: {
type: Boolean,
default: false
@@ -262,7 +266,9 @@
handleScroll(event) {
if (!this.$_scrollDirty) {
this.$_scrollDirty = true;
- requestAnimationFrame(() => {
+ if (this.$_updateTimeout) return
+
+ const requestUpdate = () => requestAnimationFrame(() => {
this.$_scrollDirty = false;
const {
continuous
@@ -272,9 +278,19 @@
// When non continous scrolling is ending, we force a refresh
if (!continuous) {
clearTimeout(this.$_refreshTimout);
- this.$_refreshTimout = setTimeout(this.handleScroll, 100);
+ this.$_refreshTimout = setTimeout(this.handleScroll, this.updateInterval + 100);
}
});
+
+ requestUpdate()
+
+ // Schedule the next update with throttling
+ if (this.updateInterval) {
+ this.$_updateTimeout = setTimeout(() => {
+ this.$_updateTimeout = 0
+ if (this.$_scrollDirty) requestUpdate();
+ }, this.updateInterval)
+ }
}
},
handleVisibilityChange(isVisible, entry) {
@@ -505,7 +521,7 @@
// After the user has finished scrolling
// Sort views so text selection is correct
clearTimeout(this.$_sortTimer);
- this.$_sortTimer = setTimeout(this.sortViews, 300);
+ this.$_sortTimer = setTimeout(this.sortViews, this.updateInterval + 300);
return {
continuous
};

View File

@ -83,9 +83,11 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
/** Scrolling recycler timer */ /** Scrolling recycler timer */
private scrollingRecyclerTimer = null as number | null; private scrollingRecyclerTimer = null as number | null;
/** View size reflow timer */ /** View size reflow timer */
private reflowRequest = false; private reflowRequest!: boolean;
/** Tick adjust timer */ /** Tick adjust timer */
private adjustRequest = false; private adjustRequest!: boolean;
/** Recycler scrolling throttle */
private recyclerScrollDirty!: boolean;
/** Get the visible ticks */ /** Get the visible ticks */
get visibleTicks() { get visibleTicks() {
@ -115,6 +117,17 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
/** Recycler scroll event, must be called by timeline */ /** Recycler scroll event, must be called by timeline */
public recyclerScrolled() { public recyclerScrolled() {
if (!this.recyclerScrollDirty) {
this.recyclerScrollDirty = true;
window.setTimeout(() => {
this.recyclerScrollDirty = false;
requestAnimationFrame(this.updateFromRecyclerScroll);
}, 100);
}
}
/** Update cursor position from recycler scroll position */
public updateFromRecyclerScroll() {
// Ignore if not initialized // Ignore if not initialized
if (!this.ticks.length) return; if (!this.ticks.length) return;
@ -556,6 +569,7 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
min-width: 100%; min-width: 100%;
min-height: 1.5px; min-height: 1.5px;
will-change: transform; will-change: transform;
transition: transform 0.1s linear;
&.st { &.st {
font-size: 0.75em; font-size: 0.75em;
@ -579,8 +593,11 @@ export default class ScrollerManager extends Mixins(GlobalMixin) {
} }
} }
} }
&:hover > .cursor.st { &:hover > .cursor {
opacity: 1; transition: none;
&.st {
opacity: 1;
}
} }
} }
</style> </style>

View File

@ -26,11 +26,12 @@
:class="{ empty: list.length === 0 }" :class="{ empty: list.length === 0 }"
:items="list" :items="list"
:emit-update="true" :emit-update="true"
:buffer="400" :buffer="800"
:skipHover="true" :skipHover="true"
key-field="id" key-field="id"
size-field="size" size-field="size"
type-field="type" type-field="type"
:updateInterval="100"
@update="scrollChange" @update="scrollChange"
@resize="handleResizeWithDelay" @resize="handleResizeWithDelay"
> >