summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Photos.vue8
-rw-r--r--src/assets/grid-sizes.js15
-rw-r--r--src/components/File.vue5
-rw-r--r--src/components/Grid.vue3
-rw-r--r--src/components/GridRow.vue77
-rw-r--r--src/components/VirtualGrid.vue168
-rw-r--r--src/mixins/GridConfig.js46
-rw-r--r--src/services/DavRequest.js19
-rw-r--r--src/services/GridConfig.js51
-rw-r--r--src/services/PhotoSearch.js26
-rw-r--r--src/services/TaggedImages.js21
-rw-r--r--src/store/timeline.js4
-rw-r--r--src/utils/ArrayChunk.js39
-rw-r--r--src/utils/fileUtils.js2
-rw-r--r--src/utils/numberUtils.js (renamed from src/utils/numberUtil.js)0
-rw-r--r--src/views/Timeline.vue91
16 files changed, 526 insertions, 49 deletions
diff --git a/src/Photos.vue b/src/Photos.vue
index acd5057a..50766d90 100644
--- a/src/Photos.vue
+++ b/src/Photos.vue
@@ -73,6 +73,14 @@ export default {
}
</script>
<style lang="scss" scoped>
+#app-content {
+ height: 100%;
+ display: flex;
+ flex-grow: 1;
+ flex-direction: column;
+ align-content: space-between;
+}
+
.app-navigation__photos::v-deep .app-navigation-entry-icon.icon-photos {
background-size: 20px;
}
diff --git a/src/assets/grid-sizes.js b/src/assets/grid-sizes.js
index 18f42ece..c17879ba 100644
--- a/src/assets/grid-sizes.js
+++ b/src/assets/grid-sizes.js
@@ -20,6 +20,9 @@
*
*/
+// for now we want to keep the same gap everywhere
+const gap = 8
+
/**
* Define the max width proportions
* The number (key) indicate the MAX size
@@ -31,53 +34,63 @@ module.exports = {
sizes: {
400: {
marginTop: 66, // same as grid-gap
- marginW: 8, // same as grid-gap
+ marginW: gap, // same as grid-gap
count: 3,
+ gap,
},
700: {
marginTop: 66,
marginW: 8, // same as grid-gap
count: 4,
+ gap,
},
1024: {
marginTop: 66,
marginW: 44,
count: 5,
+ gap,
},
1280: {
marginTop: 66,
marginW: 44,
count: 4,
+ gap,
},
1440: {
marginTop: 88,
marginW: 66,
count: 5,
+ gap,
},
1600: {
marginTop: 88,
marginW: 66,
count: 6,
+ gap,
},
2048: {
marginTop: 88,
marginW: 66,
count: 7,
+ gap,
},
2560: {
marginTop: 88,
marginW: 88,
count: 8,
+ gap,
},
3440: {
marginTop: 88,
marginW: 88,
count: 9,
+ gap,
},
max: {
marginTop: 88,
marginW: 88,
count: 10,
+ gap,
},
},
}
diff --git a/src/components/File.vue b/src/components/File.vue
index 60d18a41..0af883cf 100644
--- a/src/components/File.vue
+++ b/src/components/File.vue
@@ -100,12 +100,15 @@ export default {
isImage() {
return this.mime.startsWith('image')
},
+ srcUrl() {
+ return generateUrl(`/core/preview?fileId=${this.fileid}&x=${256}&y=${256}&a=true&v=${this.etag}`)
+ },
},
created() {
// Allow us to cancel the img loading on destroy
// use etag to force cache reload if file changed
- this.img.src = generateUrl(`/core/preview?fileId=${this.fileid}&x=${256}&y=${256}&a=true&v=${this.etag}`)
+ this.img.src = this.srcUrl
this.img.addEventListener('load', () => {
this.src = this.img.src
})
diff --git a/src/components/Grid.vue b/src/components/Grid.vue
index 85023f5a..822ecd10 100644
--- a/src/components/Grid.vue
+++ b/src/components/Grid.vue
@@ -43,7 +43,6 @@ export default {
display: grid;
align-items: center;
justify-content: center;
- gap: 8px;
grid-template-columns: repeat(10, 1fr);
position: relative;
@@ -69,6 +68,7 @@ $previous: 0;
$count: map-get($config, 'count');
$marginTop: map-get($config, 'marginTop');
$marginW: map-get($config, 'marginW');
+ $gap: map-get($config, 'gap');
// if this is the last entry, only use min-width
$rule: '(min-width: #{$previous}px) and (max-width: #{$size}px)';
@@ -78,6 +78,7 @@ $previous: 0;
@media #{$rule} {
.photos-grid {
+ gap: #{$gap}px;
padding: #{$marginTop}px #{$marginW}px #{$marginW}px #{$marginW}px;
grid-template-columns: repeat($count, 1fr);
}
diff --git a/src/components/GridRow.vue b/src/components/GridRow.vue
new file mode 100644
index 00000000..6ba385da
--- /dev/null
+++ b/src/components/GridRow.vue
@@ -0,0 +1,77 @@
+<!--
+ - @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
+ -
+ - @author John Molakvoæ <skjnldsv@protonmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+
+<template>
+ <!-- Folder content -->
+ <transition-group
+ class="photos-grid-row"
+ role="grid"
+ name="list"
+ tag="div">
+ <slot />
+ </transition-group>
+</template>
+
+<script>
+export default {
+ name: 'GridRow',
+}
+</script>
+
+<style scoped lang="scss">
+.photos-grid-row {
+ display: grid;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ margin-bottom: 8px;
+ grid-template-columns: repeat(10, 1fr);
+ position: relative;
+}
+
+.list-move {
+ transition: transform 2s;
+}
+
+// TODO: use mixins/GridSizes as soon as node-sass supports it
+// needs node-sass 5.0 (with libsass 3.6)
+// https://github.com/sass/node-sass/pull/2312
+$previous: 0;
+@each $size, $config in get('sizes') {
+ $count: map-get($config, 'count');
+ $marginTop: map-get($config, 'marginTop');
+ $marginW: map-get($config, 'marginW');
+
+ // if this is the last entry, only use min-width
+ $rule: '(min-width: #{$previous}px) and (max-width: #{$size}px)';
+ @if $size == 'max' {
+ $rule: '(min-width: #{$previous}px)';
+ }
+
+ @media #{$rule} {
+ .photos-grid-row {
+ grid-template-columns: repeat($count, 1fr);
+ }
+ }
+ $previous: $size;
+}
+</style>
diff --git a/src/components/VirtualGrid.vue b/src/components/VirtualGrid.vue
new file mode 100644
index 00000000..26501a0d
--- /dev/null
+++ b/src/components/VirtualGrid.vue
@@ -0,0 +1,168 @@
+
+<template>
+ <Grid ref="grid">
+ <span v-show="shownFirstRow > 0"
+ ref="filler-top"
+ key="filler-top"
+ class="grid-filler grid-filler--top"
+ role="none"
+ :style="{paddingBottom: topPadding}" />
+ <component :is="component(item)"
+ v-for="(item, index) in shownList"
+ :key="item.fileid"
+ :ref="`item-${index}`"
+ :class="`row-${getRowNumber(index)}`"
+ v-bind="props(item)" />
+ <span v-show="shownLastRow < lastRow"
+ ref="filler-bottom"
+ key="filler-bottom"
+ class="grid-filler grid-filler--bottom"
+ role="none"
+ :style="{paddingBottom: bottomPadding}" />
+ </Grid>
+</template>
+
+<script>
+import debounce from 'debounce'
+import Grid from './Grid'
+import GridConfigMixin from '../mixins/GridConfig'
+
+export default {
+ name: 'VirtualGrid',
+ components: {
+ Grid,
+ },
+ mixins: [GridConfigMixin],
+
+ props: {
+ list: {
+ type: Array,
+ default: () => ([]),
+ },
+ props: {
+ type: Function,
+ default: () => ({}),
+ },
+ component: {
+ type: Function,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ shownFirstRow: 0,
+ shownLastRow: this.getRowNumber(this.list.length - 1),
+ }
+ },
+
+ computed: {
+
+ shownList() {
+ return this.list.filter((item, index) => this.isVisible(index))
+ },
+
+ /**
+ * Calculate the top filler needed padding
+ * to compensate for the hidden items
+ * @returns {string}
+ */
+ topPadding() {
+ return `${this.shownFirstRow * 100}%`
+ },
+ /**
+ * Calculate the bottom filler needed padding
+ * to compensate for the hidden items
+ * Because bottomShift indicate the index of the last visible item,
+ * we need to calcuta ehow any rows there is to compensate
+ * between bottomShift and the end of the list
+ * @returns {string}
+ */
+ bottomPadding() {
+ return `${(this.lastRow - this.shownLastRow) * 100}%`
+ },
+
+ lastRow() {
+ return this.getRowNumber(this.list.length - 1)
+ },
+ },
+
+ created() {
+ window.addEventListener('scroll', this.onDocumentScroll)
+ },
+ mounted() {
+ this.onDocumentScroll()
+ },
+ beforeDestroy() {
+ window.removeEventListener('scroll', this.onDocumentScroll)
+ },
+
+ methods: {
+ debounceOnDocumentScroll: debounce(function() {
+ this.onDocumentScroll()
+ }, 50),
+
+ /**
+ * Handle document scroll
+ * Detect first visible/hidden to implement virtual scrolling
+ */
+ onDocumentScroll() {
+
+ // get the row height
+ const gridContainer = this.$refs.grid.$el
+ const gridStyles = getComputedStyle(gridContainer)
+ const rowHeight = parseFloat(gridStyles.gridTemplateColumns.split(' ')[0], 10)
+
+ // scrolled content
+ // rounding up to tens to make sure we only detect changes by steps of 10px
+ const scrolled = this.roundToTen(window.pageYOffset - this.gridConfig.marginTop)
+
+ // adding one above and one under to have a trigger area of one row
+ const shownFirstRow = Math.floor(scrolled / (rowHeight + this.gridConfig.gap)) - 1
+ const shownLastRow = Math.ceil(window.innerHeight / rowHeight) + shownFirstRow + 1
+
+ this.shownFirstRow = Math.max(shownFirstRow, 0) // the first shown row cannot be negative
+ this.shownLastRow = Math.min(shownLastRow, this.lastRow) // the last shown row cannot be lower than the last row
+
+ if (this.shownLastRow >= this.lastRow) {
+ this.$emit('bottomReached')
+ }
+
+ },
+
+ isVisible(index) {
+ const row = this.getRowNumber(index)
+ return row >= this.shownFirstRow && row < this.shownLastRow + 1
+ },
+
+ /**
+ * Return the row number of the provided index
+ *
+ * @param {number} index the index
+ * @returns {number}
+ */
+ getRowNumber(index) {
+ // in case the grid config is not here yet, let's
+ const count = this.gridConfig ? this.gridConfig.count : this.list.length
+ return Math.floor(index / count)
+ },
+
+ /**
+ * Round the provided number to a tens of its value
+ *
+ * @param {number} number the number to round
+ * @returns {number}
+ */
+ roundToTen(number) {
+ return Math.floor(number / 10) * 10
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.grid-filler {
+ // put the filler at the end of the row to put the next one into a new line
+ grid-column-end: -1;
+}
+</style>
diff --git a/src/mixins/GridConfig.js b/src/mixins/GridConfig.js
new file mode 100644
index 00000000..e7b18817
--- /dev/null
+++ b/src/mixins/GridConfig.js
@@ -0,0 +1,46 @@
+/**
+ * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import getGridConfig from '../services/GridConfig'
+
+/**
+ * Get the current used grid config
+ */
+export default {
+ data() {
+ return {
+ gridConfig: {},
+ }
+ },
+
+ created() {
+ getGridConfig.$on('changed', val => {
+ this.gridConfig = val
+ })
+ console.debug('Current grid config', getGridConfig.gridConfig)
+ this.gridConfig = getGridConfig.gridConfig
+ },
+
+ beforeDestroy() {
+ getGridConfig.$off('changed', this.gridConfig)
+ },
+}
diff --git a/src/services/DavRequest.js b/src/services/DavRequest.js
index 9a2ca05a..79c7c586 100644
--- a/src/services/DavRequest.js
+++ b/src/services/DavRequest.js
@@ -19,20 +19,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+const props = `
+ <oc:fileid />
+ <d:getlastmodified />
+ <d:getetag />
+ <d:getcontenttype />
+ <d:getcontentlength />
+ <nc:has-preview />
+ <oc:favorite />
+ <d:resourcetype />`
+export { props }
export default `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:prop>
- <d:getlastmodified />
- <d:getetag />
- <d:getcontenttype />
- <oc:fileid />
- <d:getcontentlength />
- <nc:has-preview />
- <oc:favorite />
- <d:resourcetype />
+ ${props}
</d:prop>
</d:propfind>`
diff --git a/src/services/GridConfig.js b/src/services/GridConfig.js
new file mode 100644
index 00000000..c3ee14b7
--- /dev/null
+++ b/src/services/GridConfig.js
@@ -0,0 +1,51 @@
+/**
+ * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import Vue from 'vue'
+import { sizes } from '../assets/grid-sizes'
+
+export default new Vue({
+ data() {
+ return {
+ gridConfig: sizes.max,
+ }
+ },
+ watch: {
+ gridConfig(val) {
+ this.$emit('changed', val)
+ },
+ },
+ created() {
+ window.addEventListener('resize', this.handleWindowResize)
+ this.handleWindowResize()
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.handleWindowResize)
+ },
+ methods: {
+ handleWindowResize() {
+ // find the first grid size that fit the current window width
+ const currentSize = Object.keys(sizes).find(size => size > document.documentElement.clientWidth)
+ this.gridConfig = sizes[currentSize]
+ },
+ },
+})
diff --git a/src/services/PhotoSearch.js b/src/services/PhotoSearch.js
index 06d8dda3..1050ff8f 100644
--- a/src/services/PhotoSearch.js
+++ b/src/services/PhotoSearch.js
@@ -24,15 +24,25 @@ import { genFileInfo } from '../utils/fileUtils'
import { getCurrentUser } from '@nextcloud/auth'
import allowedMimes from './AllowedMimes'
import client from './DavClient'
+import { props } from './DavRequest'
+import { sizes } from '../assets/grid-sizes'
/**
* List files from a folder and filter out unwanted mimes
*
* @param {boolean} [onlyFavorites=false] not used
* @param {Object} [options] used for the cancellable requests
+ * @param {number} [options.page=0] which page to start (starts at 0)
+ * @param {number} [options.perPage] how many to display per page default is 5 times the max number per line from the grid-sizes config file
+ * @param {boolean} [options.full=false] get full data of the files
* @returns {Array} the file list
*/
export default async function(onlyFavorites = false, options = {}) {
+ // default function options
+ options = Object.assign({}, {
+ page: 0, // start at the first page
+ perPage: sizes.max.count * 10, // ten rows of the max width
+ }, options)
const prefixPath = `/files/${getCurrentUser().uid}`
@@ -65,18 +75,12 @@ export default async function(onlyFavorites = false, options = {}) {
<d:searchrequest xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns"
+ xmlns:ns="https://github.com/icewind1991/SearchDAV/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:basicsearch>
<d:select>
<d:prop>
- <d:getlastmodified />
- <d:getetag />
- <d:getcontenttype />
- <oc:fileid />
- <d:getcontentlength />
- <nc:has-preview />
- <oc:favorite />
- <d:resourcetype />
+ ${props}
</d:prop>
</d:select>
<d:from>
@@ -104,7 +108,11 @@ export default async function(onlyFavorites = false, options = {}) {
<d:prop><d:getlastmodified/></d:prop>
<d:descending/>
</d:order>
- </d:orderby>
+ </d:orderby>
+ <d:limit>
+ <d:nresults>${options.perPage}</d:nresults>
+ <ns:firstresult>${options.page * options.perPage}</ns:firstresult>
+ </d:limit>
</d:basicsearch>
</d:searchrequest>`,
deep: true,
diff --git a/src/services/TaggedImages.js b/src/services/TaggedImages.js
index 5fe4b3ef..4488dc88 100644
--- a/src/services/TaggedImages.js
+++ b/src/services/TaggedImages.js
@@ -46,6 +46,8 @@ import { genFileInfo } from '../utils/fileUtils'
import { getCurrentUser } from '@nextcloud/auth'
import client from './DavClient'
+import { props } from './DavRequest'
+
/**
* Get tagged files based on provided tag id
*
@@ -64,24 +66,7 @@ export default async function(id, options = {}) {
xmlns:nc="http://nextcloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:prop>
- <d:getlastmodified />
- <d:getetag />
- <d:getcontenttype />
- <d:resourcetype />
- <oc:fileid />
- <oc:permissions />
- <oc:size />
- <d:getcontentlength />
- <nc:has-preview />
- <nc:mount-type />
- <nc:is-encrypted />
- <ocs:share-permissions />
- <oc:tags />
- <oc:favorite />
- <oc:comments-unread />
- <oc:owner-id />
- <oc:owner-display-name />
- <oc:share-types />
+ ${props}
</d:prop>
<oc:filter-rules>
<oc:systemtag>${id}</oc:systemtag>
diff --git a/src/store/timeline.js b/src/store/timeline.js
index c343d764..35d6ff2b 100644
--- a/src/store/timeline.js
+++ b/src/store/timeline.js
@@ -32,9 +32,9 @@ const mutations = {
* @param {Array} files the store mutations
*/
updateTimeline(state, files) {
- state.timeline = files
+ state.timeline.push(...files
.map(file => file.fileid)
- .filter(id => id >= 0)
+ .filter(id => id >= 0))
},
}
diff --git a/src/utils/ArrayChunk.js b/src/utils/ArrayChunk.js
new file mode 100644
index 00000000..ff212228
--- /dev/null
+++ b/src/utils/ArrayChunk.js
@@ -0,0 +1,39 @@
+/**
+ * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const arrayRange = function(n) {
+ // Array.range(5) --> [0,1,2,3,4]
+ return Array.apply(null, Array(n)).map((x, i) => i)
+}
+
+/**
+ * Split an array into chunks
+ *
+ * @param {Array} arr an array to split
+ * @param {number} count lenght of the chunk
+ * @returns {Array}
+ */
+export default function(arr = [], count = 5) {
+ return arrayRange(Math.ceil(arr.length / count)).map((x, i) =>
+ arr.slice(i * count, i * count + count)
+ )
+}
diff --git a/src/utils/fileUtils.js b/src/utils/fileUtils.js
index a04b9945..50e6168d 100644
--- a/src/utils/fileUtils.js
+++ b/src/utils/fileUtils.js
@@ -20,7 +20,7 @@
*
*/
import camelcase from 'camelcase'
-import { isNumber } from './numberUtil'
+import { isNumber } from './numberUtils'
/**
* Get an url encoded path
diff --git a/src/utils/numberUtil.js b/src/utils/numberUtils.js
index 0c3a96e5..0c3a96e5 100644
--- a/src/utils/numberUtil.js
+++ b/src/utils/numberUtils.js
diff --git a/src/views/Timeline.vue b/src/views/Timeline.vue
index df47f1ea..51533763 100644
--- a/src/views/Timeline.vue
+++ b/src/views/Timeline.vue
@@ -33,29 +33,35 @@
</EmptyContent>
<!-- Folder content -->
- <Grid v-else-if="!loading">
- <File v-for="file in fileList" :key="file.fileid" v-bind="file" />
- </Grid>
+ <VirtualGrid v-else-if="!loading"
+ :list="fileList"
+ :component="getComponent"
+ :loading-page="loadingPage"
+ :props="getProps"
+ @bottomReached="onBottomReached" />
</template>
<script>
import { mapGetters } from 'vuex'
+import debounce from 'debounce'
import getPhotos from '../services/PhotoSearch'
import EmptyContent from '../components/EmptyContent'
import File from '../components/File'
-import Grid from '../components/Grid'
+import VirtualGrid from '../components/VirtualGrid'
import cancelableRequest from '../utils/CancelableRequest'
+import arrayToChunk from '../utils/ArrayChunk'
+import GridConfigMixin from '../mixins/GridConfig'
export default {
name: 'Timeline',
components: {
EmptyContent,
- File,
- Grid,
+ VirtualGrid,
},
+ mixins: [GridConfigMixin],
props: {
loading: {
type: Boolean,
@@ -69,8 +75,11 @@ export default {
data() {
return {
- error: null,
cancelRequest: () => {},
+ done: false,
+ error: null,
+ page: 0,
+ loadingPage: false,
}
},
@@ -91,6 +100,11 @@ export default {
isEmpty() {
return this.fileList.length === 0
},
+
+ // the list chunked in rows for the virtual list
+ chunkedList() {
+ return arrayToChunk(this.fileList, this.gridConfig.count)
+ },
},
watch: {
@@ -111,6 +125,11 @@ export default {
methods: {
async fetchContent() {
+ // only one simultaneous page load
+ if (this.loadingPage) {
+ return
+ }
+
// cancel any pending requests
this.cancelRequest('Changed view')
@@ -122,6 +141,7 @@ export default {
this.$emit('update:loading', true)
}
this.error = null
+ this.loadingPage = true
// init cancellable request
const { request, cancel } = cancelableRequest(getPhotos)
@@ -129,9 +149,20 @@ export default {
try {
// get content and current folder info
- const files = await request(this.onlyFavorites)
+ const files = await request(this.onlyFavorites, {
+ page: this.page,
+ perPage: this.gridConfig.count * 5, // we load 5 rows,
+ })
this.$store.dispatch('updateTimeline', files)
this.$store.dispatch('appendFiles', files)
+
+ // next time we load this script, we load the next page if the list returned
+ if (files.length === this.gridConfig.coun