diff options
author | Corentin Mors <corentin.mors@dashlane.com> | 2020-10-13 17:16:11 +0300 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2020-11-15 11:32:22 +0300 |
commit | 5d13d217c6d7226b58d53bcefcafc30293906b23 (patch) | |
tree | e126a8c1b7cda0da6ac7b7305b78f3362547d17c /src | |
parent | f6243c14ca3a16384645b0db9da7b53776e2c4db (diff) |
Readd timeline caching
Signed-off-by: Corentin Mors <corentin.mors@dashlane.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/components/FileVirtualGrid.vue | 12 | ||||
-rw-r--r-- | src/views/Timeline.vue | 159 |
2 files changed, 97 insertions, 74 deletions
diff --git a/src/components/FileVirtualGrid.vue b/src/components/FileVirtualGrid.vue index 1143adc0..afa1a522 100644 --- a/src/components/FileVirtualGrid.vue +++ b/src/components/FileVirtualGrid.vue @@ -77,8 +77,8 @@ export default { openViewer() { OCA.Viewer.open({ path: this.item.injected.filename, - list: this.filterOnlyViewableFiles(this.item.injected.list()), - loadMore: async() => this.filterOnlyViewableFiles(await this.item.injected.loadMore()), + list: this.item.injected.list, + loadMore: async() => await this.item.injected.loadMore(true), }) }, @@ -86,14 +86,6 @@ export default { onLoad() { this.loaded = true }, - - /** Function to remove all elements in the list that are not images/videos (such as titles) - * @param {Array} list List of elements - * @returns {Array} List of elements that can be rendered by viewer - */ - filterOnlyViewableFiles(list) { - return list.filter(item => item.injected.filename).map(item => item.injected) - }, }, } diff --git a/src/views/Timeline.vue b/src/views/Timeline.vue index 23033fc4..6813b28a 100644 --- a/src/views/Timeline.vue +++ b/src/views/Timeline.vue @@ -45,6 +45,7 @@ <div class="grid-container"> <VirtualGrid ref="virtualgrid" + :items="contentList" :update-function="getContent" :get-column-count="() => gridConfig.count" :get-grid-gap="() => gridConfig.gap" @@ -55,6 +56,7 @@ <script> import * as moment from 'moment' +import { mapGetters } from 'vuex' import getPhotos from '../services/PhotoSearch' @@ -99,22 +101,85 @@ export default { cancelRequest: null, done: false, error: null, - loadingPage: false, - isEmpty: false, + page: 0, lastSection: '', } }, + computed: { + // global lists + ...mapGetters([ + 'files', + 'timeline', + ]), + // list of loaded medias + fileList() { + return this.timeline.map((fileId) => this.files[fileId]) + }, + // list of displayed content in the grid (titles + medias) + contentList() { + /** The goal of this flat map is to return an array of images separated by titles (months) + * ie: [{month1}, {image1}, {image2}, {month2}, {image3}, {image4}, {image5}] + * First we get the current month+year of the image + * We compare it to the previous image month+year + * If there is a difference we have to insert a title object before the current image + * If it's equal we just add the current image to the array + * Note: the injected param of objects are used to pass custom params to the grid lib + * In our case injected could be an image/video (aka file) or a title (year/month) + * Note2: titles are rendered full width and images are rendered on 1 column and 256x256 ratio + */ + return this.fileList.flatMap((file, index) => { + const finalArray = [] + const currentSection = this.getFormatedDate(file.lastmod, 'YYYY MMMM') + if ( + currentSection + !== this.getFormatedDate(this.timeline[index - 1]?.lastmod, 'YYYY MMMM') + && (this.lastSection !== currentSection) + ) { + finalArray.push({ + id: `title-${index}`, + injected: { + year: this.getFormatedDate(file.lastmod, 'YYYY'), + month: this.getFormatedDate(file.lastmod, 'MMMM'), + }, + height: 90, + columnSpan: 0, // means full width + newRow: true, + renderComponent: SeparatorVirtualGrid, + }) + this.lastSection = currentSection // we keep track of the last section for the next batch + } + finalArray.push({ + id: `img-${file.fileid}`, + injected: { + ...file, + list: this.fileList, + loadMore: this.getContent, + }, + width: 256, + height: 256, + columnSpan: 1, + renderComponent: FileVirtualGrid, + }) + return finalArray + }) + }, + // is current folder empty? + isEmpty() { + return this.fileList.length === 0 + }, + }, + watch: { async onlyFavorites() { // reset component this.resetState() + this.getContent() }, }, - async beforeMount() { - this.$emit('update:loading', false) - this.loadingPage = false + beforeMount() { + this.getContent() }, beforeDestroy() { @@ -125,9 +190,13 @@ export default { }, methods: { - async getContent(params) { + /** Return next batch of data depending on global offset + * @param {boolean} doReturn Returns a Promise with the list instead of a boolean + * @returns {Promise<boolean>} Returns a Promise with a boolean that stops infinite loading + */ + async getContent(doReturn) { if (this.done) { - return Promise.resolve([]) + return Promise.resolve(true) } // cancel any pending requests @@ -135,6 +204,11 @@ export default { this.cancelRequest('Changed view') } + // if we don't already have some cached data let's show a loader + if (this.timeline.length === 0) { + this.$emit('update:loading', true) + } + // done loading even with errors const { request, cancel } = cancelableRequest(getPhotos) this.cancelRequest = cancel @@ -144,65 +218,25 @@ export default { try { // Load next batch of images const files = await request(this.onlyFavorites, { - page: params.offset, // offset is incremented +1 by the virtualgrid lib + page: this.page, // offset is incremented +1 by the virtualgrid lib perPage: numberOfImagesPerBatch, }) - // If first batch of images is empty, there is no images - if (files.length === params.offset === 0) { - this.isEmpty = true - } - // If we get less files than requested that means we got to the end if (files.length !== numberOfImagesPerBatch) { this.done = true } - /** The goal of this flat map is to return an array of images separated by titles (months) - * ie: [{month1}, {image1}, {image2}, {month2}, {image3}, {image4}, {image5}] - * First we get the current month+year of the image - * We compare it to the previous image month+year - * If there is a difference we have to insert a title object before the current image - * If it's equal we just add the current image to the array - * Note: the injected param of objects are used to pass custom params to the grid lib - * In our case injected could be an image/video (aka file) or a title (year/month) - * Note2: titles are rendered full width and images are rendered on 1 column and 256x256 ratio - */ - return files.flatMap((file, index) => { - const finalArray = [] - const currentSection = this.getFormatedDate(file.lastmod, 'YYYY MMMM') - if ( - currentSection - !== this.getFormatedDate(files[index - 1]?.lastmod, 'YYYY MMMM') - && (this.lastSection !== currentSection) - ) { - finalArray.push({ - id: `title-${index}`, - injected: { - year: this.getFormatedDate(file.lastmod, 'YYYY'), - month: this.getFormatedDate(file.lastmod, 'MMMM'), - }, - height: 90, - columnSpan: 0, // means full width - newRow: true, - renderComponent: SeparatorVirtualGrid, - }) - this.lastSection = currentSection // we keep track of the last section for the next batch - } - finalArray.push({ - id: `img-${file.fileid}`, - injected: { - ...file, - list: this.$refs.virtualgrid.getCurrentItems, - loadMore: this.$refs.virtualgrid.loadMoreData, - }, - width: 256, - height: 256, - columnSpan: 1, - renderComponent: FileVirtualGrid, - }) - return finalArray - }) + this.$store.dispatch('updateTimeline', files) + this.$store.dispatch('appendFiles', files) + + this.page += 1 + + if (doReturn) { + return Promise.resolve(files) + } + + return Promise.resolve(false) } catch (error) { if (error.response && error.response.status) { if (error.response.status === 404) { @@ -213,17 +247,14 @@ export default { } else { this.error = error } - } else if (params.offset === 0) { // if we get an error at first batch we assume list is empty - this.isEmpty = true } // cancelled request, moving on... console.error('Error fetching timeline', error) - return Promise.resolve([]) + return Promise.resolve(true) } finally { // done loading even with errors this.$emit('update:loading', false) - this.loadingPage = false this.cancelRequest = null } }, @@ -234,9 +265,9 @@ export default { resetState() { this.$store.dispatch('resetTimeline') this.done = false - this.isEmpty = false this.error = null - this.loadingPage = false + this.page = 0 + this.$emit('update:loading', true) this.$refs.virtualgrid.resetGrid() }, |