refactor: use object for scrollermanager
parent
05e0d7818d
commit
420d2efd3b
|
@ -15,64 +15,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NcActions :inline="1">
|
<NcActions :inline="1">
|
||||||
<NcActionButton
|
<NcActionButton v-for="action of getActions()" :key="action.name"
|
||||||
:aria-label="t('memories', 'Delete')"
|
:aria-label="action.name"
|
||||||
@click="deleteSelection">
|
@click="action.callback(selection)">
|
||||||
{{ t('memories', 'Delete') }}
|
{{ action.name }}
|
||||||
<template #icon> <Delete :size="20" /> </template>
|
<template #icon> <component :is="action.icon" :size="20" /> </template>
|
||||||
</NcActionButton>
|
|
||||||
<NcActionButton
|
|
||||||
:aria-label="t('memories', 'Download')"
|
|
||||||
@click="downloadSelection" close-after-click>
|
|
||||||
{{ t('memories', 'Download') }}
|
|
||||||
<template #icon> <Download :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
<NcActionButton
|
|
||||||
:aria-label="t('memories', 'Favorite')"
|
|
||||||
@click="favoriteSelection" close-after-click>
|
|
||||||
{{ t('memories', 'Favorite') }}
|
|
||||||
<template #icon> <Star :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
|
|
||||||
<template v-if="allowArchive()">
|
|
||||||
<NcActionButton
|
|
||||||
v-if="!routeIsArchive()"
|
|
||||||
:aria-label="t('memories', 'Archive')"
|
|
||||||
@click="archiveSelection" close-after-click>
|
|
||||||
{{ t('memories', 'Archive') }}
|
|
||||||
<template #icon> <ArchiveIcon :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
<NcActionButton
|
|
||||||
v-else
|
|
||||||
:aria-label="t('memories', 'Unarchive')"
|
|
||||||
@click="archiveSelection" close-after-click>
|
|
||||||
{{ t('memories', 'Unarchive') }}
|
|
||||||
<template #icon> <UnarchiveIcon :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<NcActionButton
|
|
||||||
:aria-label="t('memories', 'Edit Date/Time')"
|
|
||||||
@click="editDateSelection" close-after-click>
|
|
||||||
{{ t('memories', 'Edit Date/Time') }}
|
|
||||||
<template #icon> <EditIcon :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
|
|
||||||
<template v-if="selection.size === 1">
|
|
||||||
<NcActionButton
|
|
||||||
:aria-label="t('memories', 'View in folder')"
|
|
||||||
@click="viewInFolder" close-after-click>
|
|
||||||
{{ t('memories', 'View in folder') }}
|
|
||||||
<template #icon> <OpenInNewIcon :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<NcActionButton
|
|
||||||
v-if="$route.name === 'people'"
|
|
||||||
:aria-label="t('memories', 'Remove from person')"
|
|
||||||
@click="removeSelectionFromPerson" close-after-click>
|
|
||||||
{{ t('memories', 'Remove from person') }}
|
|
||||||
<template #icon> <CloseIcon :size="20" /> </template>
|
|
||||||
</NcActionButton>
|
</NcActionButton>
|
||||||
</NcActions>
|
</NcActions>
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,23 +30,26 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator';
|
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator';
|
||||||
import { IHeadRow, IPhoto } from '../types';
|
import GlobalMixin from '../mixins/GlobalMixin';
|
||||||
|
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { NcActions, NcActionButton } from '@nextcloud/vue';
|
import { NcActions, NcActionButton } from '@nextcloud/vue';
|
||||||
|
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
|
||||||
|
import { IHeadRow, IPhoto, ISelectionAction } from '../types';
|
||||||
|
|
||||||
|
import * as dav from "../services/DavRequests";
|
||||||
import EditDate from "./modal/EditDate.vue"
|
import EditDate from "./modal/EditDate.vue"
|
||||||
|
|
||||||
import Star from 'vue-material-design-icons/Star.vue';
|
import StarIcon from 'vue-material-design-icons/Star.vue';
|
||||||
import Download from 'vue-material-design-icons/Download.vue';
|
import DownloadIcon from 'vue-material-design-icons/Download.vue';
|
||||||
import Delete from 'vue-material-design-icons/Delete.vue';
|
import DeleteIcon from 'vue-material-design-icons/Delete.vue';
|
||||||
import EditIcon from 'vue-material-design-icons/ClockEdit.vue';
|
import EditIcon from 'vue-material-design-icons/ClockEdit.vue';
|
||||||
import ArchiveIcon from 'vue-material-design-icons/PackageDown.vue';
|
import ArchiveIcon from 'vue-material-design-icons/PackageDown.vue';
|
||||||
import UnarchiveIcon from 'vue-material-design-icons/PackageUp.vue';
|
import UnarchiveIcon from 'vue-material-design-icons/PackageUp.vue';
|
||||||
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue';
|
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue';
|
||||||
import CloseIcon from 'vue-material-design-icons/Close.vue';
|
import CloseIcon from 'vue-material-design-icons/Close.vue';
|
||||||
|
|
||||||
import GlobalMixin from '../mixins/GlobalMixin';
|
type Selection = Map<number, IPhoto>;
|
||||||
import * as dav from "../services/DavRequests";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
|
@ -107,20 +57,15 @@ import * as dav from "../services/DavRequests";
|
||||||
NcActionButton,
|
NcActionButton,
|
||||||
EditDate,
|
EditDate,
|
||||||
|
|
||||||
Star,
|
|
||||||
Download,
|
|
||||||
Delete,
|
|
||||||
EditIcon,
|
|
||||||
ArchiveIcon,
|
|
||||||
UnarchiveIcon,
|
|
||||||
OpenInNewIcon,
|
|
||||||
CloseIcon,
|
CloseIcon,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class SelectionHandler extends Mixins(GlobalMixin) {
|
export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
@Prop() public selection: Map<number, IPhoto>;
|
@Prop() public selection: Selection;
|
||||||
@Prop() public heads: { [dayid: number]: IHeadRow };
|
@Prop() public heads: { [dayid: number]: IHeadRow };
|
||||||
|
|
||||||
|
private readonly defaultActions: ISelectionAction[];
|
||||||
|
|
||||||
@Emit('refresh')
|
@Emit('refresh')
|
||||||
refresh() {}
|
refresh() {}
|
||||||
|
|
||||||
|
@ -130,6 +75,63 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
@Emit('updateLoading')
|
@Emit('updateLoading')
|
||||||
updateLoading(delta: number) {}
|
updateLoading(delta: number) {}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
// Make default actions
|
||||||
|
this.defaultActions = [
|
||||||
|
{
|
||||||
|
name: t('memories', 'Delete'),
|
||||||
|
icon: DeleteIcon,
|
||||||
|
callback: this.deleteSelection.bind(this),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Download'),
|
||||||
|
icon: DownloadIcon,
|
||||||
|
callback: this.downloadSelection.bind(this),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Favorite'),
|
||||||
|
icon: StarIcon,
|
||||||
|
callback: this.favoriteSelection.bind(this),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Archive'),
|
||||||
|
icon: ArchiveIcon,
|
||||||
|
callback: this.archiveSelection.bind(this),
|
||||||
|
if: () => this.allowArchive() && !this.routeIsArchive(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Unarchive'),
|
||||||
|
icon: UnarchiveIcon,
|
||||||
|
callback: this.archiveSelection.bind(this),
|
||||||
|
if: () => this.allowArchive() && this.routeIsArchive(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Edit Date/Time'),
|
||||||
|
icon: EditIcon,
|
||||||
|
callback: this.editDateSelection.bind(this),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'View in folder'),
|
||||||
|
icon: OpenInNewIcon,
|
||||||
|
callback: this.viewInFolder.bind(this),
|
||||||
|
if: () => this.selection.size === 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: t('memories', 'Remove from person'),
|
||||||
|
icon: CloseIcon,
|
||||||
|
callback: this.removeSelectionFromPerson.bind(this),
|
||||||
|
if: () => this.$route.name === 'people',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the actions list */
|
||||||
|
private getActions(): ISelectionAction[] {
|
||||||
|
return this.defaultActions.filter(a => !a.if || a.if());
|
||||||
|
}
|
||||||
|
|
||||||
/** Clear all selected photos */
|
/** Clear all selected photos */
|
||||||
public clearSelection(only?: IPhoto[]) {
|
public clearSelection(only?: IPhoto[]) {
|
||||||
const heads = new Set<IHeadRow>();
|
const heads = new Set<IHeadRow>();
|
||||||
|
@ -199,32 +201,32 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
/**
|
/**
|
||||||
* Download the currently selected files
|
* Download the currently selected files
|
||||||
*/
|
*/
|
||||||
private async downloadSelection() {
|
private async downloadSelection(selection: Selection) {
|
||||||
if (this.selection.size >= 100) {
|
if (selection.size >= 100) {
|
||||||
if (!confirm(this.t("memories", "You are about to download a large number of files. Are you sure?"))) {
|
if (!confirm(this.t("memories", "You are about to download a large number of files. Are you sure?"))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await dav.downloadFilesByIds(Array.from(this.selection.keys()));
|
await dav.downloadFilesByIds(Array.from(selection.keys()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if all files selected currently are favorites
|
* Check if all files selected currently are favorites
|
||||||
*/
|
*/
|
||||||
private allSelectedFavorites() {
|
private allSelectedFavorites(selection: Selection) {
|
||||||
return Array.from(this.selection.values()).every(p => p.flag & this.c.FLAG_IS_FAVORITE);
|
return Array.from(selection.values()).every(p => p.flag & this.c.FLAG_IS_FAVORITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Favorite the currently selected photos
|
* Favorite the currently selected photos
|
||||||
*/
|
*/
|
||||||
private async favoriteSelection() {
|
private async favoriteSelection(selection: Selection) {
|
||||||
try {
|
try {
|
||||||
const val = !this.allSelectedFavorites();
|
const val = !this.allSelectedFavorites(selection);
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
for await (const favIds of dav.favoriteFilesByIds(Array.from(this.selection.keys()), val)) {
|
for await (const favIds of dav.favoriteFilesByIds(Array.from(selection.keys()), val)) {
|
||||||
favIds.forEach(id => {
|
favIds.forEach(id => {
|
||||||
const photo = this.selection.get(id);
|
const photo = selection.get(id);
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -245,8 +247,8 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
/**
|
/**
|
||||||
* Delete the currently selected photos
|
* Delete the currently selected photos
|
||||||
*/
|
*/
|
||||||
private async deleteSelection() {
|
private async deleteSelection(selection: Selection) {
|
||||||
if (this.selection.size >= 100) {
|
if (selection.size >= 100) {
|
||||||
if (!confirm(this.t("memories", "You are about to delete a large number of files. Are you sure?"))) {
|
if (!confirm(this.t("memories", "You are about to delete a large number of files. Are you sure?"))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -254,9 +256,9 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
for await (const delIds of dav.deleteFilesByIds(Array.from(this.selection.keys()))) {
|
for await (const delIds of dav.deleteFilesByIds(Array.from(selection.keys()))) {
|
||||||
const delPhotos = delIds.map(id => this.selection.get(id));
|
const delPhotos = delIds.map(id => selection.get(id));
|
||||||
await this.delete(delPhotos);
|
this.delete(delPhotos);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -268,18 +270,18 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
/**
|
/**
|
||||||
* Open the edit date dialog
|
* Open the edit date dialog
|
||||||
*/
|
*/
|
||||||
private async editDateSelection() {
|
private async editDateSelection(selection: Selection) {
|
||||||
(<any>this.$refs.editDate).open(Array.from(this.selection.values()));
|
(<any>this.$refs.editDate).open(Array.from(selection.values()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the files app with the selected file (one)
|
* Open the files app with the selected file (one)
|
||||||
* Opens a new window.
|
* Opens a new window.
|
||||||
*/
|
*/
|
||||||
private async viewInFolder() {
|
private async viewInFolder(selection: Selection) {
|
||||||
if (this.selection.size !== 1) return;
|
if (selection.size !== 1) return;
|
||||||
|
|
||||||
const photo: IPhoto = this.selection.values().next().value;
|
const photo: IPhoto = selection.values().next().value;
|
||||||
const f = await dav.getFiles([photo.fileid]);
|
const f = await dav.getFiles([photo.fileid]);
|
||||||
if (f.length === 0) return;
|
if (f.length === 0) return;
|
||||||
|
|
||||||
|
@ -292,8 +294,8 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
/**
|
/**
|
||||||
* Archive the currently selected photos
|
* Archive the currently selected photos
|
||||||
*/
|
*/
|
||||||
private async archiveSelection() {
|
private async archiveSelection(selection: Selection) {
|
||||||
if (this.selection.size >= 100) {
|
if (selection.size >= 100) {
|
||||||
if (!confirm(this.t("memories", "You are about to touch a large number of files. Are you sure?"))) {
|
if (!confirm(this.t("memories", "You are about to touch a large number of files. Are you sure?"))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -301,13 +303,13 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
for await (let delIds of dav.archiveFilesByIds(Array.from(this.selection.keys()), !this.routeIsArchive())) {
|
for await (let delIds of dav.archiveFilesByIds(Array.from(selection.keys()), !this.routeIsArchive())) {
|
||||||
delIds = delIds.filter(x => x);
|
delIds = delIds.filter(x => x);
|
||||||
if (delIds.length === 0) {
|
if (delIds.length === 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const delPhotos = delIds.map(id => this.selection.get(id));
|
const delPhotos = delIds.map(id => selection.get(id));
|
||||||
await this.delete(delPhotos);
|
this.delete(delPhotos);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -316,13 +318,9 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Archive is allowed only on timeline routes */
|
/** Archive is not allowed only on folder routes */
|
||||||
private allowArchive() {
|
private allowArchive() {
|
||||||
return this.$route.name === 'timeline' ||
|
return this.$route.name !== 'folders';
|
||||||
this.$route.name === 'favorites' ||
|
|
||||||
this.$route.name === 'videos' ||
|
|
||||||
this.$route.name === 'thisday' ||
|
|
||||||
this.$route.name === 'archive';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Is archive route */
|
/** Is archive route */
|
||||||
|
@ -333,7 +331,7 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
/**
|
/**
|
||||||
* Remove currently selected photos from person
|
* Remove currently selected photos from person
|
||||||
*/
|
*/
|
||||||
private async removeSelectionFromPerson() {
|
private async removeSelectionFromPerson(selection: Selection) {
|
||||||
// Make sure route is valid
|
// Make sure route is valid
|
||||||
const { user, name } = this.$route.params;
|
const { user, name } = this.$route.params;
|
||||||
if (this.$route.name !== "people" || !user || !name) {
|
if (this.$route.name !== "people" || !user || !name) {
|
||||||
|
@ -343,8 +341,8 @@ export default class SelectionHandler extends Mixins(GlobalMixin) {
|
||||||
// Run query
|
// Run query
|
||||||
try {
|
try {
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
for await (let delIds of dav.removeFaceImages(user, name, Array.from(this.selection.keys()))) {
|
for await (let delIds of dav.removeFaceImages(user, name, Array.from(selection.keys()))) {
|
||||||
const delPhotos = delIds.filter(x => x).map(id => this.selection.get(id));
|
const delPhotos = delIds.filter(x => x).map(id => selection.get(id));
|
||||||
this.delete(delPhotos);
|
this.delete(delPhotos);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
13
src/types.ts
13
src/types.ts
|
@ -1,3 +1,5 @@
|
||||||
|
import { VueConstructor } from "vue";
|
||||||
|
|
||||||
export type IFileInfo = {
|
export type IFileInfo = {
|
||||||
/** Database file ID */
|
/** Database file ID */
|
||||||
fileid: number;
|
fileid: number;
|
||||||
|
@ -162,3 +164,14 @@ export type TopMatterFolder = TopMatter & {
|
||||||
path: string;
|
path: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ISelectionAction = {
|
||||||
|
/** Display text */
|
||||||
|
name: string;
|
||||||
|
/** Icon component */
|
||||||
|
icon: VueConstructor;
|
||||||
|
/** Action to perform */
|
||||||
|
callback: (selection: Map<number, IPhoto>) => void;
|
||||||
|
/** Condition to check for including */
|
||||||
|
if?: () => boolean;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue