try fixing scroll position after image download on iOS PWA

This commit is contained in:
heikomat 2022-08-27 00:31:49 +02:00 committed by Michael Mayer
parent c35a827634
commit 01b548613b
9 changed files with 73 additions and 18 deletions

View file

@ -116,7 +116,10 @@ Vue.use(Dialogs);
window.popStateDetected = false;
window.addEventListener("popstate", (event) => {
window.popStateDetected = true;
console.log("popstate detected");
// give components time to react to popStateDetected in `created` or '$route'-watcher
setTimeout(() => {
window.popStateDetected = false;
});
});
Vue.use(Router);
@ -143,9 +146,6 @@ const router = new Router({
});
router.beforeEach((to, from, next) => {
to.params.backNavigationUsed = window.popStateDetected;
window.popStateDetected = false;
if (document.querySelector(".v-dialog--active.v-dialog--fullscreen")) {
// Disable back button in full-screen viewers and editors.
next(false);

View file

@ -102,7 +102,7 @@ class Viewer {
const options = {
index: index,
history: false,
history: true,
preload: [1, 1],
focus: true,
modal: true,

View file

@ -33,7 +33,10 @@
:data-index="index"
class="flex xs12 sm6 md4 lg3 xlg2 xxxl1 d-flex"
>
<div v-if="index < firstVisibleElementIndex || index > lastVisibileElementIndex" class="accent lighten-3 result placeholder">
<div v-if="index < firstVisibleElementIndex || index > lastVisibileElementIndex"
:data-uid="photo.UID"
class="accent lighten-3 result placeholder"
>
<div class="accent lighten-2 image"/>
<div v-if="photo.Quality < 3 && context === 'review'" style="width: 100%; height: 34px"/>
<div class="pa-3 card-details">

View file

@ -38,7 +38,10 @@
re-layout all elements in the list when the children of one of them changes
-->
<div class="image-container">
<div v-if="index < firstVisibleElementIndex || index > lastVisibileElementIndex" class="accent lighten-2 result image" />
<div v-if="index < firstVisibleElementIndex || index > lastVisibileElementIndex"
:data-uid="photo.UID"
class="accent lighten-2 result image"
/>
<div v-else
:key="photo.Hash"
tile

View file

@ -301,7 +301,7 @@ export default {
}
},
created() {
if (!this.$route.matched.params.backNavigationUsed) {
if (!window.popStateDetected) {
this.setOffset(0);
}
this.search();

View file

@ -204,7 +204,7 @@ export default {
},
},
created() {
if (!this.$route.matched.params.backNavigationUsed) {
if (!window.popStateDetected) {
this.setOffset(0);
}
this.search();

View file

@ -249,7 +249,7 @@ export default {
}
},
created() {
if (!this.$route.matched.params.backNavigationUsed) {
if (!window.popStateDetected) {
this.setOffset(0);
}
this.search();

View file

@ -118,6 +118,7 @@ export default {
results: [],
loading: false,
complete: false,
open: false,
dirty: false,
batchSize: batchSize > 160 ? 480 : batchSize * 3
},
@ -145,6 +146,7 @@ export default {
},
watch: {
'$route'() {
console.log('route changed', this.$route);
const query = this.$route.query;
this.filter.q = query['q'] ? query['q'] : '';
@ -168,6 +170,14 @@ export default {
this.subscriptions.push(Event.subscribe("import.completed", (ev, data) => this.onImportCompleted(ev, data)));
this.subscriptions.push(Event.subscribe("photos", (ev, data) => this.onUpdate(ev, data)));
this.subscriptions.push(Event.subscribe("viewer.show", (ev, data) => {
this.viewer.open = true;
}));
this.subscriptions.push(Event.subscribe("viewer.hide", (ev, data) => {
this.viewer.open = false;
}));
this.subscriptions.push(Event.subscribe("touchmove.top", () => this.refresh()));
this.subscriptions.push(Event.subscribe("touchmove.bottom", () => this.loadMore()));
},
@ -177,6 +187,17 @@ export default {
}
},
methods: {
searchCount() {
const offset = parseInt(window.localStorage.getItem("photos_offset"));
if(this.offset > 0 || !offset) {
return this.batchSize;
}
return offset + this.batchSize;
},
setOffset(offset) {
this.offset = offset;
window.localStorage.setItem("photos_offset", offset);
},
viewType() {
let queryParam = this.$route.query['view'] ? this.$route.query['view'] : "";
let storedType = window.localStorage.getItem("photos_view");
@ -250,6 +271,7 @@ export default {
*
* preferVideo is true, when the user explicitly clicks the live-image-icon.
*/
window.localStorage.setItem("last_opened_photo", selected.UID);
if (preferVideo && selected.Type === MediaLive || selected.Type === MediaVideo || selected.Type === MediaAnimated) {
if (selected.isPlayable()) {
this.$viewer.play({video: selected});
@ -290,22 +312,23 @@ export default {
}
Photo.search(params).then(response => {
this.results = Photo.mergeResponse(this.results, response);
this.complete = (response.count < count);
this.results = this.dirty ? response.models : Photo.mergeResponse(this.results, response);
this.complete = (response.count < response.limit);
this.scrollDisabled = this.complete;
if (this.complete) {
this.offset = offset;
this.setOffset(response.offset);
if (this.results.length > 1) {
this.$notify.info(this.$gettextInterpolate(this.$gettext("%{n} pictures found"), {n: this.results.length}));
}
} else if (this.results.length >= Photo.limit()) {
this.offset = offset;
this.setOffset(response.offset);
this.complete = true;
this.scrollDisabled = true;
this.$notify.warn(this.$gettext("Can't load more, limit reached"));
} else {
this.setOffset(response.offset + response.limit);
this.offset = offset + count;
this.page++;
@ -386,7 +409,7 @@ export default {
},
searchParams() {
const params = {
count: this.batchSize,
count: this.searchCount(),
offset: this.offset,
merged: true,
};
@ -413,6 +436,19 @@ export default {
this.loadMore();
},
search() {
/**
* search is called on mount or route change. If the route changed to an
* open viewer, no search is required. There is no reason to do an
* initial results load, if the results aren't currently visible
*/
if (this.viewer.open) {
return;
}
if (!window.popStateDetected) {
window.localStorage.removeItem("last_opened_photo");
this.setOffset(0);
}
this.scrollDisabled = true;
// Don't query the same data more than once
@ -432,11 +468,11 @@ export default {
const params = this.searchParams();
Photo.search(params).then(response => {
this.offset = this.batchSize;
this.offset = response.limit;
this.results = response.models;
this.viewer.results = [];
this.viewer.complete = false;
this.complete = (response.count < this.batchSize);
this.complete = (response.count < response.limit);
this.scrollDisabled = this.complete;
if (this.complete) {
@ -454,6 +490,19 @@ export default {
if (this.$root.$el.clientHeight <= window.document.documentElement.clientHeight + 300) {
this.$emit("scrollRefresh");
}
console.log('viewer', this.viewer.open);
const lastOpenedPhotoId = window.localStorage.getItem("last_opened_photo");
console.log('lastOpenedPhotoId', lastOpenedPhotoId);
if (!this.viewer.open && lastOpenedPhotoId) {
window.localStorage.removeItem("last_opened_photo");
this.$nextTick(() => {
document.querySelector(`[data-uid="${lastOpenedPhotoId}"]`)?.scrollIntoView({
behavior: 'auto',
block: 'center',
inline: 'center'
});
});
}
});
}
}).finally(() => {

View file

@ -190,7 +190,7 @@ export default {
}
},
created() {
if (!this.$route.matched.params.backNavigationUsed) {
if (!window.popStateDetected) {
this.setOffset(0);
}
const token = this.$route.params.token;