Port album picker

old-stable24
Varun Patil 2022-10-26 22:25:04 -07:00
parent 8d3f2a1cf6
commit 6087e5fb0a
3 changed files with 259 additions and 0 deletions

View File

@ -27,6 +27,7 @@
<!-- Selection Modals -->
<EditDate ref="editDate" @refresh="refresh" />
<FaceMoveModal ref="faceMoveModal" @moved="deletePhotos" :updateLoading="updateLoading" />
<AddToAlbumModal ref="addToAlbumModal" />
</div>
</template>
@ -45,6 +46,7 @@ import { getCurrentUser } from '@nextcloud/auth';
import * as dav from "../services/DavRequests";
import EditDate from "./modal/EditDate.vue"
import FaceMoveModal from "./modal/FaceMoveModal.vue"
import AddToAlbumModal from "./modal/AddToAlbumModal.vue"
import StarIcon from 'vue-material-design-icons/Star.vue';
import DownloadIcon from 'vue-material-design-icons/Download.vue';
@ -55,6 +57,7 @@ import UnarchiveIcon from 'vue-material-design-icons/PackageUp.vue';
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue';
import CloseIcon from 'vue-material-design-icons/Close.vue';
import MoveIcon from 'vue-material-design-icons/ImageMove.vue';
import AlbumsIcon from 'vue-material-design-icons/ImageAlbum.vue';
type Selection = Map<number, IPhoto>;
@ -64,6 +67,7 @@ type Selection = Map<number, IPhoto>;
NcActionButton,
EditDate,
FaceMoveModal,
AddToAlbumModal,
CloseIcon,
},
@ -126,6 +130,11 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
callback: this.viewInFolder.bind(this),
if: () => this.selection.size === 1,
},
{
name: t('memories', 'Add to album'),
icon: AlbumsIcon,
callback: this.addToAlbum.bind(this),
},
{
name: t('memories', 'Move to another person'),
icon: MoveIcon,
@ -335,6 +344,13 @@ export default class SelectionHandler extends Mixins(GlobalMixin, UserConfig) {
return this.$route.name === 'archive';
}
/**
* Move selected photos to album
*/
private async addToAlbum(selection: Selection) {
(<any>this.$refs.addToAlbumModal).open(Array.from(selection.values()));
}
/**
* Move selected photos to another person
*/

View File

@ -0,0 +1,63 @@
<template>
<Modal @close="close" size="normal" v-if="show">
<template #title>
{{ t('memories', 'Add to album') }}
</template>
<div class="outer">
<AlbumPicker @select="selectAlbum" />
</div>
</Modal>
</template>
<script lang="ts">
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator';
import { showError } from '@nextcloud/dialogs';
import { IAlbum, IPhoto, ITag } from '../../types';
import AlbumPicker from './AlbumPicker.vue';
import Modal from './Modal.vue';
import GlobalMixin from '../../mixins/GlobalMixin';
import client from '../../services/DavClient';
import * as dav from '../../services/DavRequests';
@Component({
components: {
Modal,
AlbumPicker,
}
})
export default class AddToAlbumModal extends Mixins(GlobalMixin) {
private show = false;
private photos: IPhoto[] = [];
@Prop()
private updateLoading: (delta: number) => void;
public open(photos: IPhoto[]) {
if (this.photos.length) {
// is processing
return;
}
this.show = true;
this.photos = photos;
}
@Emit('close')
public close() {
this.photos = [];
this.show = false;
}
public async selectAlbum(album: IAlbum) {
console.log('selectAlbum', album);
}
}
</script>
<style lang="scss" scoped>
.outer {
margin-top: 15px;
}
</style>

View File

@ -0,0 +1,180 @@
<!--
- @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
-
- @author Louis Chemineau <louis@chmn.me>
-
- @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->
<template>
<div v-if="!showAlbumCreationForm" class="album-picker">
<NcLoadingIcon v-if="loadingAlbums" class="loading-icon" />
<ul class="albums-container">
<NcListItem v-for="album in albums"
:key="album.name"
class="album"
:title="album.name"
:aria-label="t('photos', 'Add selection to album {albumName}', {albumName: album.name})"
@click="pickAlbum(album)">
<template slot="icon">
<img v-if="album.last_added_photo !== -1" class="album__image" :src="album.last_added_photo | toCoverUrl">
<div v-else class="album__image album__image--placeholder">
<ImageMultiple :size="32" />
</div>
</template>
<template slot="subtitle">
{{ n('photos', '%n item', '%n items', album.count) }}
<!-- TODO: finish collaboration -->
<!-- {{ n('photos', 'Share with %n user', 'Share with %n users', album.isShared) }}-->
</template>
</NcListItem>
</ul>
<NcButton :aria-label="t('photos', 'Create a new album.')"
class="new-album-button"
type="tertiary"
@click="showAlbumCreationForm = true">
<template #icon>
<Plus />
</template>
{{ t('photos', 'Create new album') }}
</NcButton>
</div>
<!-- <AlbumForm v-else
:display-back-button="true"
:title="t('photos', 'New album')"
@back="showAlbumCreationForm = false"
@done="albumCreatedHandler" /> -->
</template>
<script lang="ts">
import { Component, Emit, Mixins } from 'vue-property-decorator';
import GlobalMixin from '../../mixins/GlobalMixin';
import Plus from 'vue-material-design-icons/Plus.vue'
import ImageMultiple from 'vue-material-design-icons/ImageMultiple.vue'
import { NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'
import { generateUrl } from '@nextcloud/router'
import { IAlbum } from '../../types';
import axios from '@nextcloud/axios'
// import AlbumForm from './AlbumForm.vue'
@Component({
components: {
Plus,
ImageMultiple,
NcButton,
NcListItem,
NcLoadingIcon,
// AlbumForm,
},
filters: {
toCoverUrl(fileId: string) {
return generateUrl(`/apps/photos/api/v1/preview/${fileId}?x=${256}&y=${256}`)
}
}
})
export default class AlbumPicker extends Mixins(GlobalMixin) {
private showAlbumCreationForm = false;
private albums: IAlbum[] = [];
private loadingAlbums = true;
mounted() {
this.loadAlbums();
}
albumCreatedHandler() {
this.showAlbumCreationForm = false
this.loadAlbums();
}
async loadAlbums() {
try {
const res = await axios.get<IAlbum[]>(generateUrl('/apps/memories/api/albums'));
this.albums = res.data;
} catch (e) {
console.error(e);
} finally {
this.loadingAlbums = false;
}
}
@Emit('select')
pickAlbum(album: IAlbum) {}
}
</script>
<style lang="scss" scoped>
.album-picker {
h2 {
display: flex;
align-items: center;
height: 60px;
.loading-icon {
margin-left: 32px;
}
}
.albums-container {
min-height: 150px;
max-height: 350px;
overflow-x: scroll;
padding: 2px;
.album {
:deep .list-item {
padding: 8px 16px;
box-sizing: border-box;
}
&:not(:last-child) {
margin-bottom: 16px;
}
&__image {
width: 40px;
height: 40px;
object-fit: cover;
border-radius: var(--border-radius);
&--placeholder {
background: var(--color-primary-light);
:deep .material-design-icon {
width: 100%;
height: 100%;
.material-design-icon__svg {
fill: var(--color-primary);
}
}
}
}
}
}
.new-album-button {
margin-top: 32px;
}
}
</style>