Refactor getFiles to use photos

old-stable24
Varun Patil 2022-10-28 15:46:13 -07:00
parent 06b5c2c29a
commit 49bf43e1f1
12 changed files with 107 additions and 80 deletions

View File

@ -276,7 +276,7 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
return;
}
}
await dav.downloadFilesByIds(Array.from(selection.keys()));
await dav.downloadFilesByIds(Array.from(selection.values()));
}
/**
@ -294,7 +294,7 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
private async favoriteSelection(selection: Selection) {
const val = !this.allSelectedFavorites(selection);
for await (const favIds of dav.favoriteFilesByIds(
Array.from(selection.keys()),
Array.from(selection.values()),
val
)) {
favIds.forEach((id) => {
@ -330,8 +330,8 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
}
}
for await (const delIds of dav.deleteFilesByIds(
Array.from(selection.keys())
for await (const delIds of dav.deletePhotos(
Array.from(selection.values())
)) {
const delPhotos = delIds.map((id) => selection.get(id));
this.deletePhotos(delPhotos);
@ -353,7 +353,7 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
if (selection.size !== 1) return;
const photo: IPhoto = selection.values().next().value;
const f = await dav.getFiles([photo.fileid]);
const f = await dav.getFiles([photo]);
if (f.length === 0) return;
const file = f[0];
@ -424,7 +424,11 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
this.updateLoading(1);
const user = this.$route.params.user;
const name = this.$route.params.name;
const gen = dav.removeFromAlbum(user, name, Array.from(selection.keys()));
const gen = dav.removeFromAlbum(
user,
name,
Array.from(selection.values())
);
for await (const delIds of gen) {
const delPhotos = delIds
.filter((p) => p)
@ -481,7 +485,7 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
for await (let delIds of dav.removeFaceImages(
user,
name,
Array.from(selection.keys())
Array.from(selection.values())
)) {
const delPhotos = delIds.filter((x) => x).map((id) => selection.get(id));
this.deletePhotos(delPhotos);

View File

@ -125,32 +125,30 @@
</template>
<script lang="ts">
import { Component, Watch, Mixins } from "vue-property-decorator";
import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType } from "../types";
import { generateUrl } from "@nextcloud/router";
import axios from "@nextcloud/axios";
import { showError } from "@nextcloud/dialogs";
import { NcEmptyContent } from "@nextcloud/vue";
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
import { generateUrl } from "@nextcloud/router";
import { NcEmptyContent } from "@nextcloud/vue";
import PeopleIcon from "vue-material-design-icons/AccountMultiple.vue";
import CheckCircle from "vue-material-design-icons/CheckCircle.vue";
import ImageMultipleIcon from "vue-material-design-icons/ImageMultiple.vue";
import ArchiveIcon from "vue-material-design-icons/PackageDown.vue";
import { Component, Mixins, Watch } from "vue-property-decorator";
import GlobalMixin from "../mixins/GlobalMixin";
import UserConfig from "../mixins/UserConfig";
import { ViewerManager } from "../services/Viewer";
import { getLayout } from "../services/Layout";
import * as dav from "../services/DavRequests";
import { getLayout } from "../services/Layout";
import * as utils from "../services/Utils";
import axios from "@nextcloud/axios";
import { ViewerManager } from "../services/Viewer";
import { IDay, IFolder, IHeadRow, IPhoto, IRow, IRowType } from "../types";
import Folder from "./frame/Folder.vue";
import Tag from "./frame/Tag.vue";
import Photo from "./frame/Photo.vue";
import TopMatter from "./top-matter/TopMatter.vue";
import OnThisDay from "./top-matter/OnThisDay.vue";
import SelectionManager from "./SelectionManager.vue";
import Tag from "./frame/Tag.vue";
import ScrollerManager from "./ScrollerManager.vue";
import ArchiveIcon from "vue-material-design-icons/PackageDown.vue";
import CheckCircle from "vue-material-design-icons/CheckCircle.vue";
import PeopleIcon from "vue-material-design-icons/AccountMultiple.vue";
import ImageMultipleIcon from "vue-material-design-icons/ImageMultiple.vue";
import SelectionManager from "./SelectionManager.vue";
import OnThisDay from "./top-matter/OnThisDay.vue";
import TopMatter from "./top-matter/TopMatter.vue";
const SCROLL_LOAD_DELAY = 100; // Delay in loading data when scrolling
const DESKTOP_ROW_HEIGHT = 200; // Height of row on desktop

View File

@ -61,11 +61,7 @@ export default class AddToAlbumModal extends Mixins(GlobalMixin) {
public async selectAlbum(album: IAlbum) {
const name = album.name || album.album_id.toString();
const gen = dav.addToAlbum(
album.user,
name,
this.photos.map((p) => p.fileid)
);
const gen = dav.addToAlbum(album.user, name, this.photos);
this.processing = true;
for await (const fids of gen) {

View File

@ -105,7 +105,7 @@ export default class FaceMoveModal extends Mixins(GlobalMixin) {
photoMap.set(photo.fileid, photo);
}
let data = await dav.getFiles(this.photos.map((p) => p.fileid));
let data = await dav.getFiles(this.photos);
// Create move calls
const calls = data.map((p) => async () => {

View File

@ -27,6 +27,12 @@ import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
import App from "./App.vue";
import router from "./router";
// Global exposed variables
declare global {
var vuerouter: typeof router;
}
globalThis.vuerouter = router;
Vue.use(VueVirtualScroller);
// https://github.com/nextcloud/photos/blob/156f280c0476c483cb9ce81769ccb0c1c6500a4e/src/main.js

View File

@ -35,17 +35,9 @@ export class ViewerManager {
// Get file infos
let fileInfos: IFileInfo[];
const ids = list.map((p) => p.fileid);
try {
this.updateLoading(1);
if (this.$route.name === "albums") {
const user = this.$route.params.user;
const name = this.$route.params.name;
fileInfos = dav.getAlbumFileInfos(list, user, name);
} else {
fileInfos = await dav.getFiles(ids);
}
fileInfos = await dav.getFiles(list);
} catch (e) {
console.error("Failed to load fileInfos", e);
showError("Failed to load fileInfos");
@ -59,8 +51,8 @@ export class ViewerManager {
// Fix sorting of the fileInfos
const itemPositions = {};
for (const [index, id] of ids.entries()) {
itemPositions[id] = index;
for (const [index, p] of list.entries()) {
itemPositions[p.fileid] = index;
}
fileInfos.sort(function (a, b) {
return itemPositions[a.fileid] - itemPositions[b.fileid];

View File

@ -3,7 +3,14 @@ import { getCurrentUser } from "@nextcloud/auth";
import { generateUrl } from "@nextcloud/router";
import { showError } from "@nextcloud/dialogs";
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
import { IAlbum, IDay, IFileInfo, IPhoto, ITag } from "../../types";
import {
IAlbum,
IDay,
IExtendedPhoto,
IFileInfo,
IPhoto,
ITag,
} from "../../types";
import { constants } from "../Utils";
import axios from "@nextcloud/axios";
import client from "../DavClient";
@ -60,16 +67,16 @@ export async function getAlbumsData(type: "1" | "2" | "3"): Promise<IDay[]> {
*
* @param user User ID of album
* @param name Name of album (or ID)
* @param fileIds List of file IDs to add
* @param photos List of photos to add
* @returns Generator
*/
export async function* addToAlbum(
user: string,
name: string,
fileIds: number[]
photos: IPhoto[]
) {
// Get files data
let fileInfos = await base.getFiles(fileIds.filter((f) => f));
let fileInfos = await base.getFiles(photos);
const albumPath = getAlbumPath(user, name);
@ -101,16 +108,16 @@ export async function* addToAlbum(
*
* @param user Owner of album
* @param name Name of album (or ID)
* @param fileIds List of file IDs to remove
* @param photos List of photos to remove
* @returns Generator
*/
export async function* removeFromAlbum(
user: string,
name: string,
fileIds: number[]
photos: IPhoto[]
) {
// Get files data
let fileInfos = await base.getFiles(fileIds.filter((f) => f));
let fileInfos = await base.getFiles(photos);
// Add each file
const calls = fileInfos.map((f) => async () => {
@ -263,25 +270,27 @@ export function getAlbumFileInfos(
albumUser: string,
albumName: string
): IFileInfo[] {
const ephotos = photos as IExtendedPhoto[];
const uid = getCurrentUser()?.uid;
const collection =
albumUser === uid
? `/photos/${uid}/albums/${albumName}`
: `/photos/${uid}/sharedalbums/${albumName} (${albumUser})`;
return photos.map((photo) => {
return ephotos.map((photo) => {
const basename =
albumUser === uid
? `${photo.fileid}-${(<any>photo).basename}`
? `${photo.fileid}-${photo.basename}`
: `${photo.fileid}-${albumName} (${albumUser})`;
return {
fileid: photo.fileid,
filename: `${collection}/${basename}`,
basename: basename,
mime: (<any>photo).mimetype,
mime: photo.mimetype,
hasPreview: true,
etag: photo.etag,
};
} as IFileInfo;
});
}

View File

@ -1,9 +1,10 @@
import { getCurrentUser } from "@nextcloud/auth";
import { showError } from "@nextcloud/dialogs";
import { translate as t } from "@nextcloud/l10n";
import { IFileInfo } from "../../types";
import { IFileInfo, IPhoto } from "../../types";
import client from "../DavClient";
import { genFileInfo } from "../FileUtils";
import { getAlbumFileInfos } from "./albums";
export const props = `
<oc:fileid />
@ -35,10 +36,19 @@ const GET_FILE_CHUNK_SIZE = 50;
/**
* Get file infos for list of files given Ids
* @param fileIds list of file ids
* @param photos list of photos
* @returns list of file infos
*/
export async function getFiles(fileIds: number[]): Promise<IFileInfo[]> {
export async function getFiles(photos: IPhoto[]): Promise<IFileInfo[]> {
// Check if albums
const route = vuerouter.currentRoute;
if (route.name === "albums") {
return getAlbumFileInfos(photos, route.params.user, route.params.name);
}
// Get file IDs array
const fileIds = photos.map((photo) => photo.fileid);
// Divide fileIds into chunks of GET_FILE_CHUNK_SIZE
const chunks = [];
for (let i = 0; i < fileIds.length; i += GET_FILE_CHUNK_SIZE) {
@ -155,22 +165,22 @@ export async function deleteFile(path: string) {
/**
* Delete all files in a given list of Ids
*
* @param fileIds list of file ids
* @param photos list of photos to delete
* @returns list of file ids that were deleted
*/
export async function* deleteFilesByIds(fileIds: number[]) {
const fileIdsSet = new Set(fileIds);
if (fileIds.length === 0) {
export async function* deletePhotos(photos: IPhoto[]) {
if (photos.length === 0) {
return;
}
const fileIdsSet = new Set(photos.map((p) => p.fileid));
// Get files data
let fileInfos: any[] = [];
let fileInfos: IFileInfo[] = [];
try {
fileInfos = await getFiles(fileIds.filter((f) => f));
fileInfos = await getFiles(photos);
} catch (e) {
console.error("Failed to get file info for files to delete", fileIds, e);
console.error("Failed to get file info for files to delete", photos, e);
showError(t("memories", "Failed to delete files."));
return;
}
@ -180,7 +190,7 @@ export async function* deleteFilesByIds(fileIds: number[]) {
const calls = fileInfos.map((fileInfo) => async () => {
try {
await deleteFile(fileInfo.filename);
return fileInfo.fileid as number;
return fileInfo.fileid;
} catch (error) {
console.error("Failed to delete", fileInfo, error);
showError(t("memories", "Failed to delete {fileName}.", fileInfo));

View File

@ -2,6 +2,7 @@ import * as base from "./base";
import { generateUrl } from "@nextcloud/router";
import { showError } from "@nextcloud/dialogs";
import { translate as t } from "@nextcloud/l10n";
import { IPhoto } from "../../types";
/**
* Download a file
@ -39,16 +40,16 @@ export async function downloadFiles(fileNames: string[]): Promise<boolean> {
/**
* Download the files given by the fileIds
* @param fileIds list of file ids
* @param photos list of photos
*/
export async function downloadFilesByIds(fileIds: number[]) {
if (fileIds.length === 0) {
export async function downloadFilesByIds(photos: IPhoto[]) {
if (photos.length === 0) {
return;
}
// Get files to download
const fileInfos = await base.getFiles(fileIds);
if (fileInfos.length !== fileIds.length) {
const fileInfos = await base.getFiles(photos);
if (fileInfos.length !== photos.length) {
showError(t("memories", "Failed to download some files."));
}
if (fileInfos.length === 0) {

View File

@ -53,16 +53,16 @@ export async function getPeopleData(): Promise<IDay[]> {
*
* @param user User ID of face
* @param name Name of face (or ID)
* @param fileIds List of file IDs to remove
* @param photos List of photos to remove
* @returns Generator
*/
export async function* removeFaceImages(
user: string,
name: string,
fileIds: number[]
photos: IPhoto[]
) {
// Get files data
let fileInfos = await base.getFiles(fileIds.filter((f) => f));
let fileInfos = await base.getFiles(photos);
// Remove each file
const calls = fileInfos.map((f) => async () => {

View File

@ -4,6 +4,7 @@ import { encodePath } from "@nextcloud/paths";
import { showError } from "@nextcloud/dialogs";
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
import axios from "@nextcloud/axios";
import { IPhoto } from "../../types";
/**
* Favorite a file
@ -34,32 +35,33 @@ export async function favoriteFile(fileName: string, favoriteState: boolean) {
/**
* Favorite all files in a given list of Ids
*
* @param fileIds list of file ids
* @param photos list of photos
* @param favoriteState the new favorite state
* @returns generator of lists of file ids that were state-changed
*/
export async function* favoriteFilesByIds(
fileIds: number[],
photos: IPhoto[],
favoriteState: boolean
) {
const fileIdsSet = new Set(fileIds);
if (fileIds.length === 0) {
if (photos.length === 0) {
return;
}
// Get files data
let fileInfos: any[] = [];
try {
fileInfos = await base.getFiles(fileIds.filter((f) => f));
fileInfos = await base.getFiles(photos);
} catch (e) {
console.error("Failed to get file info", fileIds, e);
console.error("Failed to get file info", photos, e);
showError(t("memories", "Failed to favorite files."));
return;
}
if (fileInfos.length !== photos.length) {
showError(t("memories", "Failed to favorite some files."));
}
// Favorite each file
fileInfos = fileInfos.filter((f) => fileIdsSet.has(f.fileid));
const calls = fileInfos.map((fileInfo) => async () => {
try {
await favoriteFile(fileInfo.filename, favoriteState);

View File

@ -17,6 +17,8 @@ export type IFileInfo = {
favorite?: boolean;
/** Vue flags */
flag?: number;
/** MIME type of file */
mime?: string;
};
export type IDay = {
@ -77,6 +79,13 @@ export type IPhoto = {
datetaken?: number;
};
export interface IExtendedPhoto extends IPhoto {
/** Base name of file */
basename: string;
/** Mime type of file */
mimetype: string;
}
export interface IFolder extends IPhoto {
/** Path to folder */
path: string;