Cache days (abandon)

cache
Varun Patil 2022-10-16 11:49:29 -07:00
parent 90f197549c
commit 71a10b7971
4 changed files with 120 additions and 24 deletions

43
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@nextcloud/paths": "^2.1.0", "@nextcloud/paths": "^2.1.0",
"@nextcloud/vue": "^7.0.0", "@nextcloud/vue": "^7.0.0",
"justified-layout": "^4.1.0", "justified-layout": "^4.1.0",
"localforage": "^1.10.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"path-posix": "^1.0.0", "path-posix": "^1.0.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
@ -6780,6 +6781,11 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
},
"node_modules/immutable": { "node_modules/immutable": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz",
@ -7482,6 +7488,14 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -7528,6 +7542,14 @@
"node": ">=8.9.0" "node": ">=8.9.0"
} }
}, },
"node_modules/localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"dependencies": {
"lie": "3.1.1"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -17243,6 +17265,11 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
},
"immutable": { "immutable": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz",
@ -17749,6 +17776,14 @@
"type-check": "~0.4.0" "type-check": "~0.4.0"
} }
}, },
"lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"requires": {
"immediate": "~3.0.5"
}
},
"lines-and-columns": { "lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -17787,6 +17822,14 @@
"json5": "^2.1.2" "json5": "^2.1.2"
} }
}, },
"localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"requires": {
"lie": "3.1.1"
}
},
"locate-path": { "locate-path": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",

View File

@ -37,6 +37,7 @@
"@nextcloud/paths": "^2.1.0", "@nextcloud/paths": "^2.1.0",
"@nextcloud/vue": "^7.0.0", "@nextcloud/vue": "^7.0.0",
"justified-layout": "^4.1.0", "justified-layout": "^4.1.0",
"localforage": "^1.10.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"path-posix": "^1.0.0", "path-posix": "^1.0.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",

View File

@ -102,6 +102,7 @@ import moment from 'moment';
import * as dav from "../services/DavRequests"; import * as dav from "../services/DavRequests";
import * as utils from "../services/Utils"; import * as utils from "../services/Utils";
import localforage from "localforage";
import justifiedLayout from "justified-layout"; import justifiedLayout from "justified-layout";
import axios from '@nextcloud/axios' import axios from '@nextcloud/axios'
import Folder from "./frame/Folder.vue"; import Folder from "./frame/Folder.vue";
@ -150,8 +151,6 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
private squareMode = false; private squareMode = false;
/** Header rows for dayId key */ /** Header rows for dayId key */
private heads: { [dayid: number]: IHeadRow } = {}; private heads: { [dayid: number]: IHeadRow } = {};
/** Original days response */
private days: IDay[] = [];
/** Computed row height */ /** Computed row height */
private rowHeight = 100; private rowHeight = 100;
@ -215,12 +214,11 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// Fit to window // Fit to window
this.handleResize(); this.handleResize();
// Add scroll listener
(this.$refs.recycler as any).$el.addEventListener('scroll', this.scrollPositionChange, false);
// Get data // Get data
await this.fetchDays(); await this.fetchDays();
// Timeline recycler init
(this.$refs.recycler as any).$el.addEventListener('scroll', this.scrollPositionChange, false);
this.scrollPositionChange();
} }
/** Reset all state */ /** Reset all state */
@ -230,7 +228,6 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
this.list = []; this.list = [];
this.numRows = 0; this.numRows = 0;
this.heads = {}; this.heads = {};
this.days = [];
this.currentStart = 0; this.currentStart = 0;
this.currentEnd = 0; this.currentEnd = 0;
this.scrollerManager.reset(); this.scrollerManager.reset();
@ -488,9 +485,11 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
let params: any = {}; let params: any = {};
try { try {
this.loading++; // this.loading++;
const startState = this.state; const startState = this.state;
const furl = generateUrl(this.appendQuery(url), params);
let data: IDay[] = []; let data: IDay[] = [];
if (this.$route.name === 'thisday') { if (this.$route.name === 'thisday') {
data = await dav.getOnThisDayData(); data = await dav.getOnThisDayData();
@ -499,7 +498,12 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
} else if (this.$route.name === 'people' && !this.$route.params.name) { } else if (this.$route.name === 'people' && !this.$route.params.name) {
data = await dav.getPeopleData(); data = await dav.getPeopleData();
} else { } else {
data = (await axios.get<IDay[]>(generateUrl(this.appendQuery(url), params))).data; const foraged = await localforage.getItem<IDay[]>(furl);
if (foraged) {
await this.processDays(foraged);
}
data = (await axios.get<IDay[]>(furl)).data;
await localforage.setItem(furl, data);
} }
if (this.state !== startState) return; if (this.state !== startState) return;
@ -508,7 +512,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
console.error(err); console.error(err);
showError(err?.response?.data?.message || err.message); showError(err?.response?.data?.message || err.message);
} finally { } finally {
this.loading--; // this.loading--;
} }
} }
@ -590,9 +594,12 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
} }
// Store globally // Store globally
this.days = data; if (this.list.length) {
this.list = list; this.replaceRows(list);
this.heads = heads; } else {
this.list = list;
this.heads = heads;
}
// Iterate the preload map // Iterate the preload map
// Now the inner detail objects are reactive // Now the inner detail objects are reactive
@ -604,6 +611,57 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// Fix view height variable // Fix view height variable
await this.scrollerManager.reflow(); await this.scrollerManager.reflow();
this.scrollPositionChange();
}
/** Replace current rows with this one gracefully */
private replaceRows(rows: IRow[]) {
// Two pointers: match heads
let pOld = 0;
let pNew = 0;
let insert = false;
let remove = false
while (pOld < this.list.length && pNew < rows.length) {
const oldRow = this.list[pOld];
const newRow = rows[pNew];
// Insert new rows
if (insert) {
this.list.splice(pOld, 0, newRow);
pOld++;
pNew++;
if (rows[pNew].type === IRowType.HEAD) {
insert = false;
}
continue;
}
// Remove old rows
if (remove) {
this.list.splice(pOld, 1);
if (this.list[pOld].type === IRowType.HEAD) {
remove = false;
}
continue;
}
// Find the next heads
if (newRow.type !== IRowType.HEAD) { pNew++; continue; }
if (oldRow.type !== IRowType.HEAD) { pOld++; continue; }
if (oldRow.dayId < newRow.dayId) {
// newRow is a new head, start insertion
insert = true;
this.heads[newRow.dayId] = newRow as IHeadRow;
} else if (oldRow.dayId > newRow.dayId) {
// Different head, remove old
remove = true;
} else {
// Same head, continue
pOld++;
pNew++;
}
}
} }
/** Fetch image data for one dayId */ /** Fetch image data for one dayId */
@ -620,7 +678,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
const data = res.data; const data = res.data;
if (this.state !== startState) return; if (this.state !== startState) return;
const day = this.days.find(d => d.dayid === dayId); const day = this.heads[dayId].day;
day.detail = data; day.detail = data;
day.count = data.length; day.count = data.length;
this.processDay(day); this.processDay(day);

View File

@ -2,7 +2,7 @@
<div class="p-outer fill-block" <div class="p-outer fill-block"
:class="{ :class="{
'selected': (data.flag & c.FLAG_SELECTED), 'selected': (data.flag & c.FLAG_SELECTED),
'p-loading': !(data.flag & c.FLAG_LOADED), 'placeholder': (data.flag & c.FLAG_PLACEHOLDER),
'leaving': (data.flag & c.FLAG_LEAVING), 'leaving': (data.flag & c.FLAG_LEAVING),
'exit-left': (data.flag & c.FLAG_EXIT_LEFT), 'exit-left': (data.flag & c.FLAG_EXIT_LEFT),
'enter-right': (data.flag & c.FLAG_ENTER_RIGHT), 'enter-right': (data.flag & c.FLAG_ENTER_RIGHT),
@ -28,8 +28,7 @@
:src="src()" :src="src()"
:key="data.fileid" :key="data.fileid"
@error="error" @error="error" />
@load="load" />
</div> </div>
</div> </div>
</template> </template>
@ -89,14 +88,9 @@ export default class Photo extends Mixins(GlobalMixin) {
return getPreviewUrl(this.data.fileid, this.data.etag, false, size) return getPreviewUrl(this.data.fileid, this.data.etag, false, size)
} }
/** Image loaded successfully */
load() {
this.data.flag |= this.c.FLAG_LOADED;
}
/** Error in loading image */ /** Error in loading image */
error(e: any) { error(e: any) {
this.data.flag |= (this.c.FLAG_LOADED | this.c.FLAG_LOAD_FAIL); this.data.flag |= this.c.FLAG_LOAD_FAIL;
} }
/** Clear timers */ /** Clear timers */
@ -284,7 +278,7 @@ div.img-outer {
transition: box-shadow 0.1s ease; transition: box-shadow 0.1s ease;
.selected > & { box-shadow: 0 0 4px 2px var(--color-primary); } .selected > & { box-shadow: 0 0 4px 2px var(--color-primary); }
.p-outer.p-loading > & { display: none; } .p-outer.placeholder > & { display: none; }
.p-outer.error & { object-fit: contain; } .p-outer.error & { object-fit: contain; }
} }
} }