Fix shared album photo viewing
parent
a463e82f83
commit
f2d61c3e07
|
@ -691,6 +691,12 @@ class ApiController extends Controller
|
||||||
{
|
{
|
||||||
$transforms = [];
|
$transforms = [];
|
||||||
|
|
||||||
|
// Add extra information, basename and mimetype
|
||||||
|
if (!$aggregateOnly && ($fields = $this->request->getParam('fields'))) {
|
||||||
|
$fields = explode(',', $fields);
|
||||||
|
$transforms[] = [$this->timelineQuery, 'transformExtraFields', $fields];
|
||||||
|
}
|
||||||
|
|
||||||
// Filter only favorites
|
// Filter only favorites
|
||||||
if ($this->request->getParam('fav')) {
|
if ($this->request->getParam('fav')) {
|
||||||
$transforms[] = [$this->timelineQuery, 'transformFavoriteFilter'];
|
$transforms[] = [$this->timelineQuery, 'transformFavoriteFilter'];
|
||||||
|
|
|
@ -43,6 +43,18 @@ class TimelineQuery
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function transformExtraFields(IQueryBuilder &$query, string $uid, array &$fields)
|
||||||
|
{
|
||||||
|
if (\in_array('basename', $fields, true)) {
|
||||||
|
$query->addSelect('f.name AS basename');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\in_array('mimetype', $fields, true)) {
|
||||||
|
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
|
||||||
|
$query->addSelect('mimetypes.mimetype');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getInfoById(int $id): array
|
public function getInfoById(int $id): array
|
||||||
{
|
{
|
||||||
$qb = $this->connection->getQueryBuilder();
|
$qb = $this->connection->getQueryBuilder();
|
||||||
|
|
|
@ -108,17 +108,17 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
|
||||||
|
|
||||||
// Make default actions
|
// Make default actions
|
||||||
this.defaultActions = [
|
this.defaultActions = [
|
||||||
{
|
|
||||||
// This is at the top because otherwise it is confusing
|
|
||||||
name: t("memories", "Remove from album"),
|
|
||||||
icon: AlbumRemoveIcon,
|
|
||||||
callback: this.removeFromAlbum.bind(this),
|
|
||||||
if: () => this.$route.name === "albums",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: t("memories", "Delete"),
|
name: t("memories", "Delete"),
|
||||||
icon: DeleteIcon,
|
icon: DeleteIcon,
|
||||||
callback: this.deleteSelection.bind(this),
|
callback: this.deleteSelection.bind(this),
|
||||||
|
if: () => !this.routeIsAlbum(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t("memories", "Remove from album"),
|
||||||
|
icon: AlbumRemoveIcon,
|
||||||
|
callback: this.removeFromAlbum.bind(this),
|
||||||
|
if: () => this.routeIsAlbum(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("memories", "Download"),
|
name: t("memories", "Download"),
|
||||||
|
@ -134,7 +134,8 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
|
||||||
name: t("memories", "Archive"),
|
name: t("memories", "Archive"),
|
||||||
icon: ArchiveIcon,
|
icon: ArchiveIcon,
|
||||||
callback: this.archiveSelection.bind(this),
|
callback: this.archiveSelection.bind(this),
|
||||||
if: () => this.allowArchive() && !this.routeIsArchive(),
|
if: () =>
|
||||||
|
this.allowArchive() && !this.routeIsArchive() && !this.routeIsAlbum(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("memories", "Unarchive"),
|
name: t("memories", "Unarchive"),
|
||||||
|
@ -151,13 +152,14 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
|
||||||
name: t("memories", "View in folder"),
|
name: t("memories", "View in folder"),
|
||||||
icon: OpenInNewIcon,
|
icon: OpenInNewIcon,
|
||||||
callback: this.viewInFolder.bind(this),
|
callback: this.viewInFolder.bind(this),
|
||||||
if: () => this.selection.size === 1,
|
if: () => this.selection.size === 1 && !this.routeIsAlbum(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("memories", "Add to album"),
|
name: t("memories", "Add to album"),
|
||||||
icon: AlbumsIcon,
|
icon: AlbumsIcon,
|
||||||
callback: this.addToAlbum.bind(this),
|
callback: this.addToAlbum.bind(this),
|
||||||
if: (self: any) => self.config_albumsEnabled,
|
if: (self: typeof this) =>
|
||||||
|
self.config_albumsEnabled && !self.routeIsAlbum(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("memories", "Move to another person"),
|
name: t("memories", "Move to another person"),
|
||||||
|
@ -402,6 +404,11 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
|
||||||
return this.$route.name === "archive";
|
return this.$route.name === "archive";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Is album route */
|
||||||
|
private routeIsAlbum() {
|
||||||
|
return this.config_albumsEnabled && this.$route.name === "albums";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move selected photos to album
|
* Move selected photos to album
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -219,7 +219,8 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
||||||
/** Nextcloud viewer proxy */
|
/** Nextcloud viewer proxy */
|
||||||
private viewerManager = new ViewerManager(
|
private viewerManager = new ViewerManager(
|
||||||
this.deleteFromViewWithAnimation.bind(this),
|
this.deleteFromViewWithAnimation.bind(this),
|
||||||
this.updateLoading.bind(this)
|
this.updateLoading.bind(this),
|
||||||
|
this.$route
|
||||||
);
|
);
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -530,6 +531,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
||||||
"album",
|
"album",
|
||||||
`${this.$route.params.user}/${this.$route.params.name}`
|
`${this.$route.params.user}/${this.$route.params.name}`
|
||||||
);
|
);
|
||||||
|
query.set("fields", "basename,mimetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create query string and append to URL
|
// Create query string and append to URL
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { IFileInfo, IPhoto } from "../types";
|
||||||
import { showError } from "@nextcloud/dialogs";
|
import { showError } from "@nextcloud/dialogs";
|
||||||
import { subscribe } from "@nextcloud/event-bus";
|
import { subscribe } from "@nextcloud/event-bus";
|
||||||
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
|
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
|
||||||
|
import { Route } from "vue-router";
|
||||||
import * as dav from "./DavRequests";
|
import * as dav from "./DavRequests";
|
||||||
|
|
||||||
// Key to store sidebar state
|
// Key to store sidebar state
|
||||||
|
@ -13,7 +14,8 @@ export class ViewerManager {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
ondelete: (photos: IPhoto[]) => void,
|
ondelete: (photos: IPhoto[]) => void,
|
||||||
private updateLoading: (delta: number) => void
|
private updateLoading: (delta: number) => void,
|
||||||
|
private $route: Route
|
||||||
) {
|
) {
|
||||||
subscribe("files:file:deleted", ({ fileid }: { fileid: number }) => {
|
subscribe("files:file:deleted", ({ fileid }: { fileid: number }) => {
|
||||||
const photo = this.photoMap.get(fileid);
|
const photo = this.photoMap.get(fileid);
|
||||||
|
@ -23,7 +25,7 @@ export class ViewerManager {
|
||||||
|
|
||||||
public async open(photo: IPhoto, list?: IPhoto[]) {
|
public async open(photo: IPhoto, list?: IPhoto[]) {
|
||||||
list = list || photo.d?.detail;
|
list = list || photo.d?.detail;
|
||||||
if (!list) return;
|
if (!list?.length) return;
|
||||||
|
|
||||||
// Repopulate map
|
// Repopulate map
|
||||||
this.photoMap.clear();
|
this.photoMap.clear();
|
||||||
|
@ -36,7 +38,14 @@ export class ViewerManager {
|
||||||
const ids = list.map((p) => p.fileid);
|
const ids = list.map((p) => p.fileid);
|
||||||
try {
|
try {
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
fileInfos = await dav.getFiles(ids);
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to load fileInfos", e);
|
console.error("Failed to load fileInfos", e);
|
||||||
showError("Failed to load fileInfos");
|
showError("Failed to load fileInfos");
|
||||||
|
@ -66,7 +75,7 @@ export class ViewerManager {
|
||||||
|
|
||||||
// Open Nextcloud viewer
|
// Open Nextcloud viewer
|
||||||
globalThis.OCA.Viewer.open({
|
globalThis.OCA.Viewer.open({
|
||||||
path: fInfo.filename, // path
|
fileInfo: fInfo,
|
||||||
list: fileInfos, // file list
|
list: fileInfos, // file list
|
||||||
canLoop: false, // don't loop
|
canLoop: false, // don't loop
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { getCurrentUser } from "@nextcloud/auth";
|
||||||
import { generateUrl } from "@nextcloud/router";
|
import { generateUrl } from "@nextcloud/router";
|
||||||
import { showError } from "@nextcloud/dialogs";
|
import { showError } from "@nextcloud/dialogs";
|
||||||
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
|
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
|
||||||
import { IAlbum, IDay, ITag } from "../../types";
|
import { IAlbum, IDay, IFileInfo, IPhoto, ITag } from "../../types";
|
||||||
import { constants } from "../Utils";
|
import { constants } from "../Utils";
|
||||||
import axios from "@nextcloud/axios";
|
import axios from "@nextcloud/axios";
|
||||||
import client from "../DavClient";
|
import client from "../DavClient";
|
||||||
|
@ -256,3 +256,32 @@ export async function renameAlbum(
|
||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get fileinfo objects from album photos */
|
||||||
|
export function getAlbumFileInfos(
|
||||||
|
photos: IPhoto[],
|
||||||
|
albumUser: string,
|
||||||
|
albumName: string
|
||||||
|
): IFileInfo[] {
|
||||||
|
const uid = getCurrentUser()?.uid;
|
||||||
|
const collection =
|
||||||
|
albumUser === uid
|
||||||
|
? `/photos/${uid}/albums/${albumName}`
|
||||||
|
: `/photos/${uid}/sharedalbums/${albumName} (${albumUser})`;
|
||||||
|
|
||||||
|
return photos.map((photo) => {
|
||||||
|
const basename =
|
||||||
|
albumUser === uid
|
||||||
|
? `${photo.fileid}-${(<any>photo).basename}`
|
||||||
|
: `${photo.fileid}-${albumName} (${albumUser})`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
fileid: photo.fileid,
|
||||||
|
filename: `${collection}/${basename}`,
|
||||||
|
basename: basename,
|
||||||
|
mime: (<any>photo).mimetype,
|
||||||
|
hasPreview: true,
|
||||||
|
etag: photo.etag,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export type IFileInfo = {
|
||||||
/** Full file name, e.g. /pi/test/Qx0dq7dvEXA.jpg */
|
/** Full file name, e.g. /pi/test/Qx0dq7dvEXA.jpg */
|
||||||
filename: string;
|
filename: string;
|
||||||
/** Original file name, e.g. /files/admin/pi/test/Qx0dq7dvEXA.jpg */
|
/** Original file name, e.g. /files/admin/pi/test/Qx0dq7dvEXA.jpg */
|
||||||
originalFilename: string;
|
originalFilename?: string;
|
||||||
/** Base name of file e.g. Qx0dq7dvEXA.jpg */
|
/** Base name of file e.g. Qx0dq7dvEXA.jpg */
|
||||||
basename: string;
|
basename: string;
|
||||||
/** Etag identifier */
|
/** Etag identifier */
|
||||||
|
@ -14,7 +14,7 @@ export type IFileInfo = {
|
||||||
/** File has preview available */
|
/** File has preview available */
|
||||||
hasPreview: boolean;
|
hasPreview: boolean;
|
||||||
/** File is marked favorite */
|
/** File is marked favorite */
|
||||||
favorite: boolean;
|
favorite?: boolean;
|
||||||
/** Vue flags */
|
/** Vue flags */
|
||||||
flag?: number;
|
flag?: number;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue