diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue
index 21f513c1..3e133962 100644
--- a/src/components/Timeline.vue
+++ b/src/components/Timeline.vue
@@ -71,8 +71,7 @@
:day="item.day"
:key="photo.fileid"
@select="selectionManager.selectPhoto"
- @delete="deleteFromViewWithAnimation"
- @clickImg="clickPhoto" />
+ @click="clickPhoto(photo)" />
@@ -103,6 +102,7 @@ import { NcEmptyContent } from '@nextcloud/vue';
import GlobalMixin from '../mixins/GlobalMixin';
import moment from 'moment';
+import { ViewerManager } from "../services/Viewer";
import * as dav from "../services/DavRequests";
import * as utils from "../services/Utils";
import justifiedLayout from "justified-layout";
@@ -179,6 +179,11 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
/** Scroller manager component */
private scrollerManager!: ScrollerManager & any;
+ /** Nextcloud viewer proxy */
+ private viewerManager = new ViewerManager(
+ this.deleteFromViewWithAnimation.bind(this),
+ this.updateLoading.bind(this));
+
mounted() {
this.selectionManager = this.$refs.selectionManager;
this.scrollerManager = this.$refs.scrollerManager;
@@ -893,11 +898,13 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
}
/** Clicking on photo */
- clickPhoto(photoComponent: any) {
+ clickPhoto(photo: IPhoto) {
+ if (photo.flag & this.c.FLAG_PLACEHOLDER) return;
+
if (this.selection.size > 0) { // selection mode
- photoComponent.toggleSelect();
+ this.selectionManager.selectPhoto(photo);
} else {
- photoComponent.openFile();
+ this.viewerManager.open(photo);
}
}
diff --git a/src/components/frame/Photo.vue b/src/components/frame/Photo.vue
index fd5da80d..27660789 100644
--- a/src/components/frame/Photo.vue
+++ b/src/components/frame/Photo.vue
@@ -15,7 +15,7 @@
import { Component, Prop, Emit, Mixins } from 'vue-property-decorator';
import { IDay, IPhoto } from "../../types";
-import { subscribe, unsubscribe } from '@nextcloud/event-bus';
-import { showError } from '@nextcloud/dialogs'
import { getPreviewUrl } from "../../services/FileUtils";
-import * as dav from "../../services/DavRequests";
import errorsvg from "../../assets/error.svg";
import GlobalMixin from '../../mixins/GlobalMixin';
@@ -58,9 +55,8 @@ export default class Photo extends Mixins(GlobalMixin) {
@Prop() data: IPhoto;
@Prop() day: IDay;
- @Emit('delete') emitDelete(remPhotos: IPhoto[]) {}
@Emit('select') emitSelect(data: IPhoto) {}
- @Emit('clickImg') emitClickImg(component: any) {}
+ @Emit('click') emitClick() {}
/** Get src for image to show */
src() {
@@ -92,88 +88,8 @@ export default class Photo extends Mixins(GlobalMixin) {
clearTimeout(this.touchTimer);
}
- /** Pass to parent */
- click() {
- this.emitClickImg(this);
- }
-
- /** Open viewer */
- async openFile() {
- // Check if this is a placeholder
- if (this.data.flag & this.c.FLAG_PLACEHOLDER) {
- return;
- }
-
- // Check if already loaded fileInfos or load
- let fileInfos = this.day.fileInfos;
- if (!fileInfos) {
- const ids = this.day.detail.map(p => p.fileid);
- try {
- fileInfos = await dav.getFiles(ids);
- } catch (e) {
- console.error('Failed to load fileInfos', e);
- }
- if (fileInfos.length === 0) {
- return;
- }
-
- // Fix sorting of the fileInfos
- const itemPositions = {};
- for (const [index, id] of ids.entries()) {
- itemPositions[id] = index;
- }
- fileInfos.sort(function (a, b) {
- return itemPositions[a.fileid] - itemPositions[b.fileid];
- });
-
- // Store in day with a original copy
- this.day.fileInfos = fileInfos;
- this.day.origFileIds = new Set(fileInfos.map(f => f.fileid));
- }
-
- // Get this photo in the fileInfos
- const photo = fileInfos.find(d => Number(d.fileid) === Number(this.data.fileid));
- if (!photo) {
- showError(this.t('memories', 'Cannot find this photo anymore!'));
- return;
- }
-
- // Key to store sidebar state
- const SIDEBAR_KEY = 'memories:sidebar-open';
-
- // Subscribe to delete events
- const deleteHandler = ({ fileid }) => {
- const photo = this.day.detail.find(p => p.fileid === fileid);
- this.emitDelete([photo]);
- };
- subscribe('files:file:deleted', deleteHandler);
-
- // Open viewer
- globalThis.OCA.Viewer.open({
- path: photo.filename, // path
- list: fileInfos, // file list
- canLoop: false, // don't loop
- onClose: () => { // on viewer close
- if (globalThis.OCA.Files.Sidebar.file) {
- localStorage.setItem(SIDEBAR_KEY, '1');
- } else {
- localStorage.removeItem(SIDEBAR_KEY);
- }
- globalThis.OCA.Files.Sidebar.close();
- unsubscribe('files:file:deleted', deleteHandler);
- },
- });
-
- // Restore sidebar state
- if (localStorage.getItem(SIDEBAR_KEY) === '1') {
- globalThis.OCA.Files.Sidebar.open(photo.filename);
- }
- }
-
toggleSelect() {
- if (this.data.flag & this.c.FLAG_PLACEHOLDER) {
- return;
- }
+ if (this.data.flag & this.c.FLAG_PLACEHOLDER) return;
this.emitSelect(this.data);
}
diff --git a/src/services/Viewer.ts b/src/services/Viewer.ts
new file mode 100644
index 00000000..9fddd61e
--- /dev/null
+++ b/src/services/Viewer.ts
@@ -0,0 +1,87 @@
+import { IFileInfo, IPhoto } from "../types";
+import { showError } from '@nextcloud/dialogs'
+import { subscribe } from '@nextcloud/event-bus';
+import { translate as t, translatePlural as n } from '@nextcloud/l10n'
+import * as dav from "./DavRequests";
+
+// Key to store sidebar state
+const SIDEBAR_KEY = 'memories:sidebar-open';
+
+export class ViewerManager {
+ /** Map from fileid to Photo */
+ private photoMap = new Map();
+
+ constructor(
+ ondelete: (photos: IPhoto[]) => void,
+ private updateLoading: (delta: number) => void,
+ ) {
+ subscribe('files:file:deleted', ({ fileid }: { fileid: number }) => {
+ const photo = this.photoMap.get(fileid);
+ ondelete([photo]);
+ });
+ }
+
+ public async open(photo: IPhoto) {
+ const day = photo.d;
+ if (!day) return;
+
+ // Repopulate map
+ this.photoMap.clear();
+ for (const p of day.detail) {
+ this.photoMap.set(p.fileid, p);
+ }
+
+ // Get file infos
+ let fileInfos: IFileInfo[];
+ const ids = day.detail.map(p => p.fileid);
+ try {
+ this.updateLoading(1);
+ fileInfos = await dav.getFiles(ids);
+ } catch (e) {
+ console.error('Failed to load fileInfos', e);
+ showError('Failed to load fileInfos');
+ return;
+ } finally {
+ this.updateLoading(-1);
+ }
+ if (fileInfos.length === 0) {
+ return;
+ }
+
+ // Fix sorting of the fileInfos
+ const itemPositions = {};
+ for (const [index, id] of ids.entries()) {
+ itemPositions[id] = index;
+ }
+ fileInfos.sort(function (a, b) {
+ return itemPositions[a.fileid] - itemPositions[b.fileid];
+ });
+
+ // Get this photo in the fileInfos
+ const fInfo = fileInfos.find(d => Number(d.fileid) === photo.fileid);
+ if (!fInfo) {
+ showError(t('memories', 'Cannot find this photo anymore!'));
+ return;
+ }
+
+ // Open Nextcloud viewer
+ globalThis.OCA.Viewer.open({
+ path: fInfo.filename, // path
+ list: fileInfos, // file list
+ canLoop: false, // don't loop
+ onClose: () => { // on viewer close
+ if (globalThis.OCA.Files.Sidebar.file) {
+ localStorage.setItem(SIDEBAR_KEY, '1');
+ } else {
+ localStorage.removeItem(SIDEBAR_KEY);
+ }
+ globalThis.OCA.Files.Sidebar.close();
+ },
+ });
+
+ // Restore sidebar state
+ if (localStorage.getItem(SIDEBAR_KEY) === '1') {
+ globalThis.OCA.Files.Sidebar.open(fInfo.filename);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index 039f1248..8150f3a8 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -24,10 +24,6 @@ export type IDay = {
rows?: IRow[];
/** List of photos for this day */
detail?: IPhoto[];
- /** WebDAV fileInfos, fetched before viewer open */
- fileInfos?: IFileInfo[];
- /** Original fileIds from fileInfos */
- origFileIds?: Set;
}
export type IPhoto = {