From 580de583468ce45d4fab3089dfb60b39ce558adc Mon Sep 17 00:00:00 2001 From: Heiko Mathes Date: Fri, 17 Jun 2022 04:44:58 +0200 Subject: [PATCH] UX: Ssearch view render performance improvements (#2433) * virtualize mosaic-view * start virtualizing parts of the list view * drastically improve mosaic component updating performance by not rendering cards if not necessary * speed up list view virtualization by preventing the rendering of vue-components * start virtualizing cards view * continue virtualizing card view * finish virtualizing cards * start moving common virtualization logic into shared file * try speeding up access to calculated photo details * remove console.log * improve accuracy of cards-placeholder elements * remove console.log * start fixing memoized values not updating on change * fixing memoized values not updating on change * remove console.logs * fix getting location info after memoizing the function * remove obsolete comment * start rendering of only visible icons in mosaic-view * continue rendering of only visible icons in mosaic-view * implement rendering of only visible icons in cards-view * implement rendering of only visible icons in list-view * memoize some photo-model functions that are called when rendering mosaic- or cards-view * fix cards sometimes getting smaller when scrolling * improve fix for cards sometimes getting smaller when scrolling * prevent rendering of no-photos-alert if photos are present * fix selection issues after implementing conditional button-rendering * speedup mosaic rendering by replacing vue components with html components * speedup cards rendering by replacing vue components with html components * speedup list rendering by replacing vue components with html components * fix removed elements leaving behind placeholders in view * speedup photo view rendering by replacing vue buttons and icons with regular html components * fix positioning of card-title in placeholder elements * fix missing icons after multiselect or select via touch * prevent flickering of favourite button on click * prevent flickering of favourite button on click * use div instead of v-flex * replace inline styles with css classes * re-add actually necessary css-classes * add size-containment to mosaic-elements to reduce re-layouting costs when virtualization replaces children * fix typo in comment * use plain html instead of components and css-classes instead of inline styles in cards.vue * improve list scrolling by not using v-data-table for a static table * fix icon-color on card-details in light-theme * fix card-details showing wrong icons with wrong height on pixel 3 * fix animated gif-previews getting out of image-bounds when hovering in firefox * fix closing brackets in mosaic view not matching opening brackets * fix live-photo icon in mosaic- cards and list components * improve render performance by replacing v-hover vue-component with css-hidden button * prevent unnecessary rerenders * prevent unnecessary rerenders * undo "prevent unnecessary rerender" because the real-world-effect is negligable * load next batch earlier to reduce change of scrolling to the end before the load finished * add explanation on why the selection-button isnt removed via v-if * remove console.log * speed up rendering by reducing amount of observed items * fix favourite-buttons in non-search views * prevent unnecessary observeItems-calls by only observing items when photos changed Co-authored-by: Heiko Mathes --- frontend/src/component/photo/cards.vue | 249 ++++++++++++----------- frontend/src/component/photo/list.vue | 252 ++++++++++++------------ frontend/src/component/photo/mosaic.vue | 186 ++++++++--------- frontend/src/css/results.css | 88 ++++++++- frontend/src/pages/photos.vue | 2 +- 5 files changed, 447 insertions(+), 330 deletions(-) diff --git a/frontend/src/component/photo/cards.vue b/frontend/src/component/photo/cards.vue index 9c3c612b3..dfae318c9 100644 --- a/frontend/src/component/photo/cards.vue +++ b/frontend/src/component/photo/cards.vue @@ -21,34 +21,29 @@ - -
-
+
+
-
+

{{ photo.Title | truncate(80) }}

-
+
{{ photo.Description }}
-
- +
+ {{ photo.getDateString(true) }}
- + @@ -57,130 +52,125 @@
- +
- - - photo_camera - $vuetify.icons.live_photo - gif - play_arrow - burst_mode - + - - zoom_in - + - - play_arrow - + - - lock - + + - - favorite - favorite_border - - + +
+ small depressed dark block :round="false" + class="action-archive text-xs-center" + :title="$gettext('Archive')" @click.stop="photo.archive()"> clear + small depressed dark block :round="false" + class="action-approve text-xs-center" + :title="$gettext('Approve')" @click.stop="photo.approve()"> check - +


@@ -227,15 +217,15 @@

-
-
- +
+
+
@@ -244,9 +234,13 @@ import download from "common/download"; import Notify from "common/notify"; import {Input, InputInvalid, ClickShort, ClickLong} from "common/input"; import {virtualizationTools} from 'common/virtualization-tools'; +import IconLivePhoto from "component/icon/live_photo.vue"; export default { name: 'PPhotoCards', + components: { + IconLivePhoto, + }, props: { photos: { type: Array, @@ -321,8 +315,16 @@ export default { if (this.$refs.items === undefined) { return; } - for (const item of this.$refs.items) { - this.intersectionObserver.observe(item); + + /** + * observing only every 5th item reduces the amount of time + * spent computing intersection by 80%. me might render up to + * 8 items more than required, but the time saved computing + * intersections is far greater than the time lost rendering + * a couple more items + */ + for (let i = 0; i < this.$refs.items.length; i += 5) { + this.intersectionObserver.observe(this.$refs.items[i]); } }, elementIndexFromIntersectionObserverEntry(entry) { @@ -335,8 +337,10 @@ export default { this.elementIndexFromIntersectionObserverEntry, ); - this.firstVisibleElementIndex = smallestIndex; - this.lastVisibileElementIndex = largestIndex; + // we observe only every 5th item, so we increase the rendered + // range here by 4 items in every directio just to be safe + this.firstVisibleElementIndex = smallestIndex - 4; + this.lastVisibileElementIndex = largestIndex + 4; }, livePlayer(photo) { return document.querySelector("#live-player-" + photo.ID); @@ -388,9 +392,19 @@ export default { if (ev.shiftKey) { this.selectRange(index); } else { - this.$clipboard.toggle(this.photos[index]); + this.toggle(this.photos[index]); } }, + toggle(photo) { + this.$clipboard.toggle(photo); + /** + * updating the clipboard does not rerender this component. Because of that + * there can be scenarios where the select-icon is missing after a change, + * for example when using touch and no hover-state changes.We therefore + * force an update to fix that. + */ + this.$forceUpdate(); + }, onOpen(ev, index, showMerged) { const inputType = this.input.eval(ev, index); @@ -412,7 +426,7 @@ export default { if (longClick || ev.shiftKey) { this.selectRange(index); } else { - this.$clipboard.toggle(this.photos[index]); + this.toggle(this.photos[index]); } } else { this.openPhoto(index, false); @@ -427,6 +441,13 @@ export default { }, selectRange(index) { this.$clipboard.addRange(index, this.photos); + /** + * updating the clipboard does not rerender this component. Because of that + * there can be scenarios where the select-icon is missing after a change, + * for example when selecting mutliple elements at once. We therefore + * force an update to fix that. + */ + this.$forceUpdate(); }, } }; diff --git a/frontend/src/component/photo/list.vue b/frontend/src/component/photo/list.vue index 3a7833d02..e201ff188 100644 --- a/frontend/src/component/photo/list.vue +++ b/frontend/src/component/photo/list.vue @@ -20,118 +20,127 @@

- +
+ + + + + + + + + + + + - > - - + + + + +
+ + {{$gettext('Title')}} + + {{$gettext('Taken')}} + + {{$gettext('Camera')}} + + {{showName ? $gettext('Name') : $gettext('Location')}} + +
+
+
+ + +
+
+
+