Adds multiple albums selection

Signed-off-by: Alexander Saltykov <temp.kroogi@gmail.com>
pull/752/head
Alexander Saltykov 2023-07-26 08:43:20 +03:00
parent 7eca2b7111
commit ccbd550ba1
3 changed files with 100 additions and 26 deletions

View File

@ -33,7 +33,7 @@
</template> </template>
{{ t('memories', 'Add to album') }} {{ t('memories', 'Add to album') }}
</NcButton> </NcButton>
<AddToAlbumModal ref="addToAlbumModal" @added="update" /> <AddToAlbumModal ref="addToAlbumModal" @added="loadAlbums" />
</div> </div>
</template> </template>

View File

@ -5,7 +5,7 @@
</template> </template>
<div class="outer"> <div class="outer">
<AlbumPicker @select="selectAlbum" :photos="photos" /> <AlbumPicker @select="selectAlbums" :photos="photos" />
<div v-if="processing"> <div v-if="processing">
<NcProgressBar :value="Math.round((photosDone * 100) / photos.length)" :error="true" /> <NcProgressBar :value="Math.round((photosDone * 100) / photos.length)" :error="true" />
@ -60,19 +60,32 @@ export default defineComponent({
this.$emit('close'); this.$emit('close');
}, },
async selectAlbum(album: IAlbum) { async selectAlbums(albums: IAlbum[]) {
if (this.processing) return; if (this.processing) return;
const processed = new Set<IPhoto>();
const photosDone = new Set<number>();
const name = album.name || album.album_id.toString(); await Promise.all(albums.map(async (album) => {
const gen = dav.addToAlbum(album.user, name, this.photos); const name = album.name || album.album_id.toString();
this.processing = true; const gen = dav.addToAlbum(album.user, name, this.photos);
this.processing = true;
for await (const fids of gen) {
this.photosDone += fids.filter((f) => f).length; for await (const fids of gen) {
this.added(this.photos.filter((p) => fids.includes(p.fileid))); fids.forEach((f) => {
} if (f) {
photosDone.add(f);
}
});
this.photos.forEach((p) => {
if (fids.includes(p.fileid)) {
processed.add(p);
}
});
}
this.photosDone = photosDone.size;
}));
const n = this.photosDone; const n = this.photosDone;
this.added(Array.from(processed));
showInfo(this.n('memories', '{n} item added to album', '{n} items added to album', n, { n })); showInfo(this.n('memories', '{n} item added to album', '{n} items added to album', n, { n }));
this.close(); this.close();
}, },

View File

@ -13,7 +13,7 @@
albumName: album.name, albumName: album.name,
}) })
" "
@click="pickAlbum(album)" @click.prevent="pickAlbum(album)"
> >
<template #icon> <template #icon>
<XImg v-if="album.last_added_photo !== -1" class="album__image" :src="toCoverUrl(album.last_added_photo)" /> <XImg v-if="album.last_added_photo !== -1" class="album__image" :src="toCoverUrl(album.last_added_photo)" />
@ -27,7 +27,7 @@
</template> </template>
<template #extra> <template #extra>
<div v-if="album.has_file" class="check-circle-icon"> <div v-if="selectedAlbums.has(album)" class="check-circle-icon">
<XImg :src="checkmarkIcon" /> <XImg :src="checkmarkIcon" />
</div> </div>
</template> </template>
@ -35,17 +35,35 @@
</NcListItem> </NcListItem>
</ul> </ul>
<NcButton <div class="actions">
:aria-label="t('memories', 'Create a new album.')" <NcButton
class="new-album-button" :aria-label="t('memories', 'Create a new album.')"
type="tertiary" class="new-album-button"
@click="showAlbumCreationForm = true" type="tertiary"
> @click="showAlbumCreationForm = true"
<template #icon> >
<Plus /> <template #icon>
</template> <Plus />
{{ t('memories', 'Create new album') }} </template>
</NcButton> {{ t('memories', 'Create new album') }}
</NcButton>
<div class="submit-btn-wrapper">
<NcButton
:aria-label="t('memories', `Add to ${selectedCount} albums.`)"
class="new-album-button"
type="primary"
@click="submit"
>
{{ t('memories', 'Add to albums') }}
</NcButton>
<span class="remove-notice" v-if="unselectedCount > 0">
{{ t('memories', 'And remove from') }} {{ n('memories', '{n} album', '{n} albums', unselectedCount , {
n: unselectedCount,
})}}
</span>
</div>
</div>
</div> </div>
<AlbumForm <AlbumForm
@ -100,6 +118,10 @@ export default defineComponent({
loadingAlbums: true, loadingAlbums: true,
photoId: -1, photoId: -1,
checkmarkIcon, checkmarkIcon,
selectedAlbums: new Set<IAlbum>(),
unselectedAlbums: new Set<IAlbum>(),
selectedCount: 0,
unselectedCount: 0,
}), }),
mounted() { mounted() {
@ -143,6 +165,9 @@ export default defineComponent({
try { try {
const res = await axios.get<IAlbum[]>(API.ALBUM_LIST(3, this.photoId)); const res = await axios.get<IAlbum[]>(API.ALBUM_LIST(3, this.photoId));
this.albums = res.data; this.albums = res.data;
this.selectedAlbums = new Set(this.albums.filter(album => album.has_file));
this.unselectedAlbums = new Set();
this.unselectedCount = 0;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} finally { } finally {
@ -151,8 +176,28 @@ export default defineComponent({
}, },
pickAlbum(album: IAlbum) { pickAlbum(album: IAlbum) {
this.$emit('select', album); if (this.selectedAlbums.has(album)) {
this.selectedAlbums.delete(album);
this.unselectedAlbums.add(album)
} else if (this.unselectedAlbums.has(album)) {
this.selectedAlbums.add(album)
this.unselectedAlbums.delete(album);
} else {
this.selectedAlbums.add(album)
}
this.unselectedCount = this.albums.reduce((acc, album) => {
if (album.has_file && this.unselectedAlbums.has(album)) {
acc += 1;
}
return acc;
}, 0); this.selectedAlbums.size;
this.selectedCount = this.selectedAlbums.size;
}, },
submit() {
this.$emit('select', Array.from(this.selectedAlbums));
}
}, },
}); });
</script> </script>
@ -231,5 +276,21 @@ export default defineComponent({
.new-album-button { .new-album-button {
margin-top: 32px; margin-top: 32px;
} }
.actions {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.submit-btn-wrapper {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.remove-notice {
font-size: small;
}
} }
</style> </style>