feat: allow dragging and dropping playlist folders to queue (#1624)

This commit is contained in:
Phan An 2022-12-07 21:35:31 +01:00 committed by GitHub
parent c6c805c007
commit 9bb4e8c1f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 10 deletions

View file

@ -3,8 +3,10 @@
class="playlist-folder"
:class="{ droppable }"
tabindex="0"
draggable="true"
@dragleave="onDragLeave"
@dragover="onDragOver"
@dragstart="onDragStart"
@drop="onDrop"
>
<a @click.prevent="toggle" @contextmenu.prevent="onContextMenu">
@ -32,7 +34,7 @@ import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
import { computed, defineAsyncComponent, ref, toRefs } from 'vue'
import { playlistFolderStore, playlistStore } from '@/stores'
import { eventBus } from '@/utils'
import { useDroppable } from '@/composables'
import { useDraggable, useDroppable } from '@/composables'
const PlaylistSidebarItem = defineAsyncComponent(() => import('./PlaylistSidebarItem.vue'))
@ -46,9 +48,12 @@ const droppableOnHatch = ref(false)
const playlistsInFolder = computed(() => playlistStore.byFolder(folder.value))
const { acceptsDrop, resolveDroppedValue } = useDroppable(['playlist'])
const { startDragging } = useDraggable('playlist-folder')
const toggle = () => (opened.value = !opened.value)
const onDragStart = (event: DragEvent) => startDragging(event, folder.value)
const onDragOver = (event: DragEvent) => {
if (!acceptsDrop(event)) return false
@ -97,7 +102,11 @@ const onDropOnHatch = async (event: DragEvent) => {
await playlistFolderStore.removePlaylistFromFolder(folder.value, playlist)
}
const onContextMenu = event => eventBus.emit('PLAYLIST_FOLDER_CONTEXT_MENU_REQUESTED', event, folder.value)
const onContextMenu = (event: MouseEvent) => eventBus.emit(
'PLAYLIST_FOLDER_CONTEXT_MENU_REQUESTED',
event,
folder.value
)
</script>
<style lang="scss" scoped>

View file

@ -16,11 +16,13 @@
import { faListOl } from '@fortawesome/free-solid-svg-icons'
import { ref } from 'vue'
import { queueStore } from '@/stores'
import { useDroppable } from '@/composables'
import { useDroppable, useMessageToaster } from '@/composables'
import SidebarItem from './SidebarItem.vue'
import { pluralize } from '@/utils'
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist', 'playlist'])
const { toastWarning, toastSuccess } = useMessageToaster()
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist', 'playlist', 'playlist-folder'])
const droppable = ref(false)
@ -32,7 +34,13 @@ const onQueueDrop = async (event: DragEvent) => {
event.preventDefault()
const songs = await resolveDroppedSongs(event) || []
songs.length && queueStore.queue(songs)
if (songs.length) {
queueStore.queue(songs)
toastSuccess(`Added ${ pluralize(songs, 'song') } to queue.`)
} else {
toastWarning('No applicable songs to queue.')
}
return false
}

View file

@ -1,8 +1,8 @@
import { arrayify, logger, pluralize } from '@/utils'
import { albumStore, artistStore, playlistStore, songStore } from '@/stores'
import { albumStore, artistStore, playlistFolderStore, playlistStore, songStore } from '@/stores'
type Draggable = Song | Song[] | Album | Artist | Playlist
const draggableTypes = <const>['songs', 'album', 'artist', 'playlist']
type Draggable = Song | Song[] | Album | Artist | Playlist | PlaylistFolder
const draggableTypes = <const>['songs', 'album', 'artist', 'playlist', 'playlist-folder']
type DraggableType = typeof draggableTypes[number]
const createGhostDragImage = (event: DragEvent, text: string): void => {
@ -33,7 +33,7 @@ export const useDraggable = (type: DraggableType) => {
return
}
let text
let text: string
let data: any
switch (type) {
@ -62,6 +62,12 @@ export const useDraggable = (type: DraggableType) => {
data = dragged.id
break
case 'playlist-folder':
dragged = <PlaylistFolder>dragged
text = dragged.name
data = dragged.id
break
default:
return
}
@ -125,8 +131,13 @@ export const useDroppable = (acceptedTypes: DraggableType[]) => {
const artist = await artistStore.resolve(<number>data)
return artist ? await songStore.fetchForArtist(artist) : <Song[]>[]
case 'playlist':
const playlist = await playlistStore.byId(<number>data)
const playlist = playlistStore.byId(<number>data)
return playlist ? await songStore.fetchForPlaylist(playlist) : <Song[]>[]
case 'playlist-folder':
const folder = playlistFolderStore.byId(<string>data)
return folder ? await songStore.fetchForPlaylistFolder(folder) : <Song[]>[]
default:
throw new Error(`Unknown drag type: ${type}`)
}
} catch (error) {
logger.error(error, event)