[web-src] Refactor details modal dialogs into separate components

This will allow to open a dialog outside of the ListItem component. Also
reduces the size of the generated DOM tree by only including one dialog
per page (per object type) and not for each list item.
This commit is contained in:
chme 2018-12-15 09:56:09 +01:00
parent 0cc4699128
commit 5e85e0b024
31 changed files with 997 additions and 506 deletions

View File

@ -5,56 +5,15 @@
<h2 class="subtitle is-7 has-text-grey"><b>{{ album.artist }}</b></h2> <h2 class="subtitle is-7 has-text-grey"><b>{{ album.artist }}</b></h2>
</div> </div>
<div class="media-right"> <div class="media-right">
<a @click="show_details_modal = true"> <slot name="actions"></slot>
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_album">{{ album.name }}</a>
</p>
<div class="content is-small">
<p v-if="album.artist && media_kind !== 'audiobook'">
<span class="heading">Album artist</span>
<a class="title is-6 has-text-link" @click="open_artist">{{ album.artist }}</a>
</p>
<p v-if="album.artist && media_kind === 'audiobook'">
<span class="heading">Album artist</span>
<span class="title is-6">{{ album.artist }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ album.track_count }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi'
export default { export default {
name: 'ListItemAlbum', name: 'ListItemAlbum',
components: { ModalDialog }, components: {},
props: ['album', 'media_kind', 'anchor'], props: ['album', 'media_kind', 'anchor'],
@ -65,25 +24,6 @@ export default {
}, },
methods: { methods: {
play: function () {
this.show_details_modal = false
webapi.player_play_uri(this.album.uri, false)
},
queue_add: function () {
this.show_details_modal = false
webapi.queue_add(this.album.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.show_details_modal = false
webapi.queue_add_next(this.album.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_album: function () { open_album: function () {
this.show_details_modal = false this.show_details_modal = false
if (this.media_kind === 'podcast') { if (this.media_kind === 'podcast') {
@ -93,11 +33,6 @@ export default {
} else { } else {
this.$router.push({ path: '/music/albums/' + this.album.id }) this.$router.push({ path: '/music/albums/' + this.album.id })
} }
},
open_artist: function () {
this.show_details_modal = false
this.$router.push({ path: '/music/artists/' + this.album.artist_id })
} }
} }
} }

View File

@ -4,83 +4,20 @@
<h1 class="title is-6">{{ artist.name }}</h1> <h1 class="title is-6">{{ artist.name }}</h1>
</div> </div>
<div class="media-right"> <div class="media-right">
<a @click="show_details_modal = true"> <slot name="actions"></slot>
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_artist">{{ artist.name }}</a>
</p>
<div class="content is-small">
<p>
<span class="heading">Albums</span>
<span class="title is-6">{{ artist.album_count }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ artist.track_count }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi'
export default { export default {
name: 'PartArtist', name: 'ListItemArtist',
components: { ModalDialog }, components: {},
props: ['artist', 'anchor'], props: ['artist', 'anchor'],
data () {
return {
show_details_modal: false
}
},
methods: { methods: {
play: function () {
this.show_details_modal = false
webapi.player_play_uri(this.artist.uri, false)
},
queue_add: function () {
this.show_details_modal = false
webapi.queue_add(this.artist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Artist tracks appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.show_details_modal = false
webapi.queue_add_next(this.artist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_artist: function () { open_artist: function () {
this.show_details_modal = false
this.$router.push({ path: '/music/artists/' + this.artist.id }) this.$router.push({ path: '/music/artists/' + this.artist.id })
} }
} }

View File

@ -4,89 +4,19 @@
<h1 class="title is-6">{{ genre.name }}</h1> <h1 class="title is-6">{{ genre.name }}</h1>
</div> </div>
<div class="media-right"> <div class="media-right">
<a @click="show_details_modal = true"> <slot name="actions"></slot>
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_genre">{{ genre.name }}</a>
</p>
<!--
<div class="content is-small">
<p>
<span class="heading">Albums</span>
<span class="title is-6">{{ genre.album_count }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ genre.track_count }}</span>
</p>
</div>
-->
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-12px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-12px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-12px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi'
export default { export default {
name: 'PartGenre', name: 'ListItemGenre',
components: { ModalDialog }, components: {},
props: [ 'genre', 'anchor' ], props: [ 'genre', 'anchor' ],
data () {
return {
show_details_modal: false
}
},
methods: { methods: {
play: function () {
this.show_details_modal = false
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.player_play_uri(data.albums.items.map(a => a.uri).join(','), false)
)
},
queue_add: function () {
this.show_details_modal = false
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.queue_add(data.albums.items.map(a => a.uri).join(',')).then(() =>
this.$store.dispatch('add_notification', { text: 'Genre albums appended to queue', type: 'info', timeout: 1500 })
)
)
},
queue_add_next: function () {
this.show_details_modal = false
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.queue_add_next(data.albums.items.map(a => a.uri).join(',')).then(() =>
this.$store.dispatch('add_notification', { text: 'Genre albums playing next', type: 'info', timeout: 1500 })
)
)
},
open_genre: function () { open_genre: function () {
this.show_details_modal = false this.show_details_modal = false
this.$router.push({ name: 'Genre', params: { genre: this.genre.name } }) this.$router.push({ name: 'Genre', params: { genre: this.genre.name } })

View File

@ -4,77 +4,19 @@
<h1 class="title is-6">{{ playlist.name }}</h1> <h1 class="title is-6">{{ playlist.name }}</h1>
</div> </div>
<div class="media-right"> <div class="media-right">
<a @click="show_details_modal = true"> <slot name="actions"></slot>
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_playlist">{{ playlist.name }}</a>
</p>
<div class="content is-small">
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ playlist.path }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi'
export default { export default {
name: 'PartPlaylist', name: 'ListItemPlaylist',
components: { ModalDialog }, components: {},
props: ['playlist'], props: ['playlist'],
data () {
return {
show_details_modal: false
}
},
methods: { methods: {
play: function () {
this.show_details_modal = false
webapi.player_play_uri(this.playlist.uri, false)
},
queue_add: function () {
this.show_details_modal = false
webapi.queue_add(this.playlist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Playlist appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.show_details_modal = false
webapi.queue_add_next(this.playlist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_playlist: function () { open_playlist: function () {
this.show_details_modal = false this.show_details_modal = false
this.$router.push({ path: '/playlists/' + this.playlist.id }) this.$router.push({ path: '/playlists/' + this.playlist.id })

View File

@ -1,6 +1,5 @@
<template> <template>
<div class="media" v-if="is_next || !show_only_next_items"> <div class="media" v-if="is_next || !show_only_next_items">
<!---->
<div class="media-left" v-if="edit_mode"> <div class="media-left" v-if="edit_mode">
<span class="icon has-text-grey fd-is-movable handle"><i class="mdi mdi-drag-horizontal mdi-18px"></i></span> <span class="icon has-text-grey fd-is-movable handle"><i class="mdi mdi-drag-horizontal mdi-18px"></i></span>
</div> </div>
@ -11,75 +10,17 @@
<h2 class="subtitle is-7" :class="{ 'has-text-primary': item.id === state.item_id, 'has-text-grey-light': !is_next, 'has-text-grey': is_next && item.id !== state.item_id }">{{ item.album }}</h2> <h2 class="subtitle is-7" :class="{ 'has-text-primary': item.id === state.item_id, 'has-text-grey-light': !is_next, 'has-text-grey': is_next && item.id !== state.item_id }">{{ item.album }}</h2>
</div> </div>
<div class="media-right"> <div class="media-right">
<a v-on:click="remove" v-if="item.id !== state.item_id && edit_mode"> <slot name="actions"></slot>
<span class="icon has-text-grey"><i class="mdi mdi-delete mdi-18px"></i></span>
</a>
<a @click="show_details_modal = true" v-if="!edit_mode">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog v-if="!edit_mode" :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
{{ item.title }}
</p>
<p class="subtitle">
{{ item.artist }}
</p>
<div class="content is-small">
<p>
<span class="heading">Album</span>
<span class="title is-6">{{ item.album }}</span>
</p>
<p v-if="item.album_artist">
<span class="heading">Album artist</span>
<span class="title is-6">{{ item.album_artist }}</span>
</p>
<p v-if="item.year > 0">
<span class="heading">Year</span>
<span class="title is-6">{{ item.year }}</span>
</p>
<p>
<span class="heading">Genre</span>
<span class="title is-6">{{ item.genre }}</span>
</p>
<p>
<span class="heading">Track / Disc</span>
<span class="title is-6">{{ item.track_number }} / {{ item.disc_number }}</span>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{ item.length_ms | duration }}</span>
</p>
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ item.path }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="remove">
<span class="icon"><i class="mdi mdi-delete mdi-18px"></i></span> <span>Remove</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi' import webapi from '@/webapi'
export default { export default {
name: 'PartQueueItem', name: 'ListItemQueueItem',
components: { ModalDialog }, components: {},
props: ['item', 'position', 'current_position', 'show_only_next_items', 'edit_mode'], props: ['item', 'position', 'current_position', 'show_only_next_items', 'edit_mode'],
@ -100,11 +41,6 @@ export default {
}, },
methods: { methods: {
remove: function () {
this.show_details_modal = false
webapi.queue_remove(this.item.id)
},
play: function () { play: function () {
this.show_details_modal = false this.show_details_modal = false
webapi.player_play({ 'item_id': this.item.id }) webapi.player_play({ 'item_id': this.item.id })

View File

@ -6,135 +6,28 @@
<h2 class="subtitle is-7 has-text-grey">{{ track.album }}</h2> <h2 class="subtitle is-7 has-text-grey">{{ track.album }}</h2>
</div> </div>
<div class="media-right"> <div class="media-right">
<a @click="show_details_modal = true"> <slot name="actions"></slot>
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<modal-dialog :show="show_details_modal" @close="show_details_modal = false">
<template slot="modal-content">
<div class="card">
<div class="card-content">
<p class="title is-4">
{{ track.title }}
</p>
<p class="subtitle">
{{ track.artist }}
</p>
<div class="content is-small">
<p>
<span class="heading">Album</span>
<a class="title is-6 has-text-link" @click="open_album">{{ track.album }}</a>
</p>
<p v-if="track.album_artist && track.media_kind !== 'audiobook'">
<span class="heading">Album artist</span>
<a class="title is-6 has-text-link" @click="open_artist">{{ track.album_artist }}</a>
</p>
<p v-if="track.date_released">
<span class="heading">Release date</span>
<span class="title is-6">{{ track.date_released | time('L')}}</span>
</p>
<p v-else-if="track.year > 0">
<span class="heading">Year</span>
<span class="title is-6">{{ track.year }}</span>
</p>
<p>
<span class="heading">Genre</span>
<span class="title is-6">{{ track.genre }}</span>
</p>
<p>
<span class="heading">Track / Disc</span>
<span class="title is-6">{{ track.track_number }} / {{ track.disc_number }}</span>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{ track.length_ms | duration }}</span>
</p>
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ track.path }}</span>
</p>
<p>
<span class="heading">Type</span>
<span class="title is-6">{{ track.media_kind }} - {{ track.data_kind }}</span>
</p>
<p>
<span class="heading">Added at</span>
<span class="title is-6">{{ track.time_added | time('L LT')}}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play_track">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</template>
</modal-dialog>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog'
import webapi from '@/webapi' import webapi from '@/webapi'
export default { export default {
name: 'PartTrack', name: 'ListItemTrack',
components: { ModalDialog }, components: {},
props: ['track', 'position', 'context_uri'], props: ['track', 'position', 'context_uri'],
data () { data () {
return { return {
show_details_modal: false
} }
}, },
methods: { methods: {
play: function () { play: function () {
this.show_details_modal = false
webapi.player_play_uri(this.context_uri, false, this.position) webapi.player_play_uri(this.context_uri, false, this.position)
},
play_track: function () {
this.show_details_modal = false
webapi.player_play_uri(this.track.uri, false)
},
queue_add: function () {
this.show_details_modal = false
webapi.queue_add(this.track.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Track appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.show_details_modal = false
webapi.queue_add_next(this.track.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_album: function () {
this.show_details_modal = false
if (this.track.media_kind === 'podcast') {
this.$router.push({ path: '/podcasts/' + this.track.album_id })
} else if (this.track.media_kind === 'audiobook') {
this.$router.push({ path: '/audiobooks/' + this.track.album_id })
} else {
this.$router.push({ path: '/music/albums/' + this.track.album_id })
}
},
open_artist: function () {
this.show_details_modal = false
this.$router.push({ path: '/music/artists/' + this.track.album_artist_id })
} }
} }
} }

View File

@ -0,0 +1,93 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_album">{{ album.name }}</a>
</p>
<div class="content is-small">
<p v-if="album.artist && media_kind !== 'audiobook'">
<span class="heading">Album artist</span>
<a class="title is-6 has-text-link" @click="open_artist">{{ album.artist }}</a>
</p>
<p v-if="album.artist && media_kind === 'audiobook'">
<span class="heading">Album artist</span>
<span class="title is-6">{{ album.artist }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ album.track_count }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogAlbum',
props: [ 'show', 'album', 'media_kind' ],
methods: {
play: function () {
this.$emit('close')
webapi.player_play_uri(this.album.uri, false)
},
queue_add: function () {
this.$emit('close')
webapi.queue_add(this.album.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.$emit('close')
webapi.queue_add_next(this.album.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_album: function () {
this.show_details_modal = false
if (this.media_kind === 'podcast') {
this.$router.push({ path: '/podcasts/' + this.album.id })
} else if (this.media_kind === 'audiobook') {
this.$router.push({ path: '/audiobooks/' + this.album.id })
} else {
this.$router.push({ path: '/music/albums/' + this.album.id })
}
},
open_artist: function () {
this.show_details_modal = false
this.$router.push({ path: '/music/artists/' + this.album.artist_id })
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,78 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_artist">{{ artist.name }}</a>
</p>
<div class="content is-small">
<p>
<span class="heading">Albums</span>
<span class="title is-6">{{ artist.album_count }}</span>
</p>
<p>
<span class="heading">Tracks</span>
<span class="title is-6">{{ artist.track_count }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogArtist',
props: [ 'show', 'artist' ],
methods: {
play: function () {
this.$emit('close')
webapi.player_play_uri(this.artist.uri, false)
},
queue_add: function () {
this.$emit('close')
webapi.queue_add(this.artist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Artist tracks appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.$emit('close')
webapi.queue_add_next(this.artist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_artist: function () {
this.$emit('close')
this.$router.push({ path: '/music/artists/' + this.artist.id })
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,74 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_genre">{{ genre.name }}</a>
</p>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-12px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-12px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-12px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogGenre',
props: [ 'show', 'genre' ],
methods: {
play: function () {
this.$emit('close')
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.player_play_uri(data.albums.items.map(a => a.uri).join(','), false)
)
},
queue_add: function () {
this.$emit('close')
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.queue_add(data.albums.items.map(a => a.uri).join(',')).then(() =>
this.$store.dispatch('add_notification', { text: 'Genre albums appended to queue', type: 'info', timeout: 1500 })
)
)
},
queue_add_next: function () {
this.$emit('close')
webapi.library_genre(this.genre.name).then(({ data }) =>
webapi.queue_add_next(data.albums.items.map(a => a.uri).join(',')).then(() =>
this.$store.dispatch('add_notification', { text: 'Genre albums playing next', type: 'info', timeout: 1500 })
)
)
},
open_genre: function () {
this.$emit('close')
this.$router.push({ name: 'Genre', params: { genre: this.genre.name } })
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,74 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
<a class="has-text-link" @click="open_playlist">{{ playlist.name }}</a>
</p>
<div class="content is-small">
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ playlist.path }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogPlaylist',
props: [ 'show', 'playlist' ],
methods: {
play: function () {
this.$emit('close')
webapi.player_play_uri(this.playlist.uri, false)
},
queue_add: function () {
this.$emit('close')
webapi.queue_add(this.playlist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Playlist appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.$emit('close')
webapi.queue_add_next(this.playlist.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_playlist: function () {
this.$emit('close')
this.$router.push({ path: '/playlists/' + this.playlist.id })
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,84 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
{{ item.title }}
</p>
<p class="subtitle">
{{ item.artist }}
</p>
<div class="content is-small">
<p>
<span class="heading">Album</span>
<span class="title is-6">{{ item.album }}</span>
</p>
<p v-if="item.album_artist">
<span class="heading">Album artist</span>
<span class="title is-6">{{ item.album_artist }}</span>
</p>
<p v-if="item.year > 0">
<span class="heading">Year</span>
<span class="title is-6">{{ item.year }}</span>
</p>
<p>
<span class="heading">Genre</span>
<span class="title is-6">{{ item.genre }}</span>
</p>
<p>
<span class="heading">Track / Disc</span>
<span class="title is-6">{{ item.track_number }} / {{ item.disc_number }}</span>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{ item.length_ms | duration }}</span>
</p>
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ item.path }}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="remove">
<span class="icon"><i class="mdi mdi-delete mdi-18px"></i></span> <span>Remove</span>
</a>
<a class="card-footer-item has-text-dark" @click="play">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogQueueItem',
props: [ 'show', 'item' ],
methods: {
remove: function () {
this.$emit('close')
webapi.queue_remove(this.item.id)
},
play: function () {
this.$emit('close')
webapi.player_play({ 'item_id': this.item.id })
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,130 @@
<template>
<div>
<transition name="fade">
<div class="modal is-active" v-if="show">
<div class="modal-background" @click="$emit('close')"></div>
<div class="modal-content fd-modal-card">
<div class="card">
<div class="card-content">
<p class="title is-4">
{{ track.title }}
</p>
<p class="subtitle">
{{ track.artist }}
</p>
<div class="content is-small">
<p>
<span class="heading">Album</span>
<a class="title is-6 has-text-link" @click="open_album">{{ track.album }}</a>
</p>
<p v-if="track.album_artist && track.media_kind !== 'audiobook'">
<span class="heading">Album artist</span>
<a class="title is-6 has-text-link" @click="open_artist">{{ track.album_artist }}</a>
</p>
<p v-if="track.date_released">
<span class="heading">Release date</span>
<span class="title is-6">{{ track.date_released | time('L')}}</span>
</p>
<p v-else-if="track.year > 0">
<span class="heading">Year</span>
<span class="title is-6">{{ track.year }}</span>
</p>
<p>
<span class="heading">Genre</span>
<span class="title is-6">{{ track.genre }}</span>
</p>
<p>
<span class="heading">Track / Disc</span>
<span class="title is-6">{{ track.track_number }} / {{ track.disc_number }}</span>
</p>
<p>
<span class="heading">Length</span>
<span class="title is-6">{{ track.length_ms | duration }}</span>
</p>
<p>
<span class="heading">Path</span>
<span class="title is-6">{{ track.path }}</span>
</p>
<p>
<span class="heading">Type</span>
<span class="title is-6">{{ track.media_kind }} - {{ track.data_kind }}</span>
</p>
<p>
<span class="heading">Added at</span>
<span class="title is-6">{{ track.time_added | time('L LT')}}</span>
</p>
</div>
</div>
<footer class="card-footer">
<a class="card-footer-item has-text-dark" @click="queue_add">
<span class="icon"><i class="mdi mdi-playlist-plus mdi-18px"></i></span> <span>Add</span>
</a>
<a class="card-footer-item has-text-dark" @click="queue_add_next">
<span class="icon"><i class="mdi mdi-playlist-play mdi-18px"></i></span> <span>Add Next</span>
</a>
<a class="card-footer-item has-text-dark" @click="play_track">
<span class="icon"><i class="mdi mdi-play mdi-18px"></i></span> <span>Play</span>
</a>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="$emit('close')"></button>
</div>
</transition>
</div>
</template>
<script>
import webapi from '@/webapi'
export default {
name: 'ModalDialogTrack',
props: ['show', 'track'],
data () {
return {
}
},
methods: {
play_track: function () {
this.$emit('close')
webapi.player_play_uri(this.track.uri, false)
},
queue_add: function () {
this.$emit('close')
webapi.queue_add(this.track.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Track appended to queue', type: 'info', timeout: 2000 })
)
},
queue_add_next: function () {
this.$emit('close')
webapi.queue_add_next(this.track.uri).then(() =>
this.$store.dispatch('add_notification', { text: 'Album tracks appended to queue', type: 'info', timeout: 2000 })
)
},
open_album: function () {
this.$emit('close')
if (this.track.media_kind === 'podcast') {
this.$router.push({ path: '/podcasts/' + this.track.album_id })
} else if (this.track.media_kind === 'audiobook') {
this.$router.push({ path: '/audiobooks/' + this.track.album_id })
} else {
this.$router.push({ path: '/music/albums/' + this.track.album_id })
}
},
open_artist: function () {
this.$emit('close')
this.$router.push({ path: '/music/artists/' + this.track.album_artist_id })
}
}
}
</script>
<style>
</style>

View File

@ -18,7 +18,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p> <p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p>
<list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri"></list-item-track> <list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -27,6 +34,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const albumData = { const albumData = {
@ -46,12 +54,15 @@ const albumData = {
export default { export default {
name: 'PageAlbum', name: 'PageAlbum',
mixins: [ LoadDataBeforeEnterMixin(albumData) ], mixins: [ LoadDataBeforeEnterMixin(albumData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
album: {}, album: {},
tracks: [] tracks: [],
show_details_modal: false,
selected_track: {}
} }
}, },
@ -63,6 +74,11 @@ export default {
play: function () { play: function () {
webapi.player_play_uri(this.album.uri, true) webapi.player_play_uri(this.album.uri, true)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -19,7 +19,14 @@
</a> </a>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="(album, index) in albums.items" :key="album.id" :album="album" :anchor="anchor(album, index)" v-if="!hide_singles || album.track_count > 2"></list-item-album> <list-item-album v-for="(album, index) in albums.items" :key="album.id" :album="album" :anchor="anchor(album, index)" v-if="!hide_singles || album.track_count > 2">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_details_modal" :album="selected_album" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -31,6 +38,7 @@ import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import IndexButtonList from '@/components/IndexButtonList' import IndexButtonList from '@/components/IndexButtonList'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
import * as types from '@/store/mutation_types' import * as types from '@/store/mutation_types'
@ -47,11 +55,14 @@ const albumsData = {
export default { export default {
name: 'PageAlbums', name: 'PageAlbums',
mixins: [ LoadDataBeforeEnterMixin(albumsData) ], mixins: [ LoadDataBeforeEnterMixin(albumsData) ],
components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemAlbum }, components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemAlbum, ModalDialogAlbum },
data () { data () {
return { return {
albums: { items: [] } albums: { items: [] },
show_details_modal: false,
selected_album: {}
} }
}, },
@ -74,6 +85,11 @@ export default {
anchor: function (album, index) { anchor: function (album, index) {
return album.name_sort.charAt(0).toUpperCase() return album.name_sort.charAt(0).toUpperCase()
},
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -10,7 +10,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ artist.album_count }} albums | <a class="has-text-link" @click="open_tracks">{{ artist.track_count }} tracks</a></p> <p class="heading has-text-centered-mobile">{{ artist.album_count }} albums | <a class="has-text-link" @click="open_tracks">{{ artist.track_count }} tracks</a></p>
<list-item-album v-for="album in albums.items" :key="album.id" :album="album"></list-item-album> <list-item-album v-for="album in albums.items" :key="album.id" :album="album">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_details_modal" :album="selected_album" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -19,6 +26,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const artistData = { const artistData = {
@ -38,12 +46,15 @@ const artistData = {
export default { export default {
name: 'PageArtist', name: 'PageArtist',
mixins: [ LoadDataBeforeEnterMixin(artistData) ], mixins: [ LoadDataBeforeEnterMixin(artistData) ],
components: { ContentWithHeading, ListItemAlbum }, components: { ContentWithHeading, ListItemAlbum, ModalDialogAlbum },
data () { data () {
return { return {
artist: {}, artist: {},
albums: {} albums: {},
show_details_modal: false,
selected_album: {}
} }
}, },
@ -54,6 +65,11 @@ export default {
play: function () { play: function () {
webapi.player_play_uri(this.albums.items.map(a => a.uri).join(','), true) webapi.player_play_uri(this.albums.items.map(a => a.uri).join(','), true)
},
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -19,7 +19,14 @@
</a> </a>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-artist v-for="(artist, index) in artists.items" :key="artist.id" :artist="artist" :anchor="anchor(artist, index)" v-if="!hide_singles || artist.track_count > (artist.album_count * 2)"></list-item-artist> <list-item-artist v-for="(artist, index) in artists.items" :key="artist.id" :artist="artist" :anchor="anchor(artist, index)" v-if="!hide_singles || artist.track_count > (artist.album_count * 2)">
<template slot="actions">
<a @click="open_dialog(artist)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-artist>
<modal-dialog-artist :show="show_details_modal" :artist="selected_artist" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -31,6 +38,7 @@ import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import IndexButtonList from '@/components/IndexButtonList' import IndexButtonList from '@/components/IndexButtonList'
import ListItemArtist from '@/components/ListItemArtist' import ListItemArtist from '@/components/ListItemArtist'
import ModalDialogArtist from '@/components/ModalDialogArtist'
import webapi from '@/webapi' import webapi from '@/webapi'
import * as types from '@/store/mutation_types' import * as types from '@/store/mutation_types'
@ -47,11 +55,14 @@ const artistsData = {
export default { export default {
name: 'PageArtists', name: 'PageArtists',
mixins: [ LoadDataBeforeEnterMixin(artistsData) ], mixins: [ LoadDataBeforeEnterMixin(artistsData) ],
components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemArtist }, components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemArtist, ModalDialogArtist },
data () { data () {
return { return {
artists: { items: [] } artists: { items: [] },
show_details_modal: false,
selected_artist: {}
} }
}, },
@ -74,6 +85,11 @@ export default {
anchor: function (artist, index) { anchor: function (artist, index) {
return artist.name_sort.charAt(0).toUpperCase() return artist.name_sort.charAt(0).toUpperCase()
},
open_dialog: function (artist) {
this.selected_artist = artist
this.show_details_modal = true
} }
} }
} }

View File

@ -14,7 +14,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p> <p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p>
<list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri"></list-item-track> <list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -23,6 +30,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const albumData = { const albumData = {
@ -42,18 +50,26 @@ const albumData = {
export default { export default {
name: 'PageAudiobook', name: 'PageAudiobook',
mixins: [ LoadDataBeforeEnterMixin(albumData) ], mixins: [ LoadDataBeforeEnterMixin(albumData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
album: {}, album: {},
tracks: [] tracks: [],
show_details_modal: false,
selected_track: {}
} }
}, },
methods: { methods: {
play: function () { play: function () {
webapi.player_play_uri(this.album.uri, false) webapi.player_play_uri(this.album.uri, false)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -6,7 +6,14 @@
<p class="heading">{{ albums.total }} audiobooks</p> <p class="heading">{{ albums.total }} audiobooks</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="album in albums.items" :key="album.id" :album="album" :media_kind="'audiobook'"></list-item-album> <list-item-album v-for="album in albums.items" :key="album.id" :album="album" :media_kind="'audiobook'">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_details_modal" :album="selected_album" :media_kind="'audiobook'" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -16,6 +23,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const albumsData = { const albumsData = {
@ -31,11 +39,21 @@ const albumsData = {
export default { export default {
name: 'PageAudiobooks', name: 'PageAudiobooks',
mixins: [ LoadDataBeforeEnterMixin(albumsData) ], mixins: [ LoadDataBeforeEnterMixin(albumsData) ],
components: { ContentWithHeading, ListItemAlbum }, components: { ContentWithHeading, ListItemAlbum, ModalDialogAlbum },
data () { data () {
return { return {
albums: {} albums: {},
show_details_modal: false,
selected_album: {}
}
},
methods: {
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -9,7 +9,14 @@
<p class="heading">albums</p> <p class="heading">albums</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="album in recently_added.items" :key="album.id" :album="album"></list-item-album> <list-item-album v-for="album in recently_added.items" :key="album.id" :album="album">
<template slot="actions">
<a @click="open_album_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_album_details_modal" :album="selected_album" @close="show_album_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav class="level"> <nav class="level">
@ -27,7 +34,14 @@
<p class="heading">tracks</p> <p class="heading">tracks</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-track v-for="track in recently_played.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri"></list-item-track> <list-item-track v-for="track in recently_played.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri">
<template slot="actions">
<a @click="open_track_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_track_details_modal" :track="selected_track" @close="show_track_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav class="level"> <nav class="level">
@ -46,6 +60,8 @@ import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const browseData = { const browseData = {
@ -65,18 +81,34 @@ const browseData = {
export default { export default {
name: 'PageBrowse', name: 'PageBrowse',
mixins: [ LoadDataBeforeEnterMixin(browseData) ], mixins: [ LoadDataBeforeEnterMixin(browseData) ],
components: { ContentWithHeading, TabsMusic, ListItemAlbum, ListItemTrack }, components: { ContentWithHeading, TabsMusic, ListItemAlbum, ListItemTrack, ModalDialogTrack, ModalDialogAlbum },
data () { data () {
return { return {
recently_added: {}, recently_added: {},
recently_played: {} recently_played: {},
show_track_details_modal: false,
selected_track: {},
show_album_details_modal: false,
selected_album: {}
} }
}, },
methods: { methods: {
open_browse: function (type) { open_browse: function (type) {
this.$router.push({ path: '/music/browse/' + type }) this.$router.push({ path: '/music/browse/' + type })
},
open_track_dialog: function (track) {
this.selected_track = track
this.show_track_details_modal = true
},
open_album_dialog: function (album) {
this.selected_album = album
this.show_album_details_modal = true
} }
} }
} }

View File

@ -8,7 +8,14 @@
<p class="heading">albums</p> <p class="heading">albums</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="album in recently_added.items" :key="album.id" :album="album"></list-item-album> <list-item-album v-for="album in recently_added.items" :key="album.id" :album="album">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_details_modal" :album="selected_album" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -19,6 +26,7 @@ import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const browseData = { const browseData = {
@ -38,11 +46,21 @@ const browseData = {
export default { export default {
name: 'PageBrowseType', name: 'PageBrowseType',
mixins: [ LoadDataBeforeEnterMixin(browseData) ], mixins: [ LoadDataBeforeEnterMixin(browseData) ],
components: { ContentWithHeading, TabsMusic, ListItemAlbum }, components: { ContentWithHeading, TabsMusic, ListItemAlbum, ModalDialogAlbum },
data () { data () {
return { return {
recently_added: {} recently_added: {},
show_details_modal: false,
selected_album: {}
}
},
methods: {
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -8,7 +8,14 @@
<p class="heading">tracks</p> <p class="heading">tracks</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-track v-for="track in recently_played.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri"></list-item-track> <list-item-track v-for="track in recently_played.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -19,6 +26,7 @@ import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const browseData = { const browseData = {
@ -38,11 +46,21 @@ const browseData = {
export default { export default {
name: 'PageBrowseType', name: 'PageBrowseType',
mixins: [ LoadDataBeforeEnterMixin(browseData) ], mixins: [ LoadDataBeforeEnterMixin(browseData) ],
components: { ContentWithHeading, TabsMusic, ListItemTrack }, components: { ContentWithHeading, TabsMusic, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
recently_played: {} recently_played: {},
show_details_modal: false,
selected_track: {}
}
},
methods: {
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -10,8 +10,15 @@
</a> </a>
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ genreAlbums.total }} albums | <a class="has-text-link" @click="open_tracks">{{ tracks }} tracks</a></p> <p class="heading has-text-centered-mobile">{{ genreAlbums.total }} albums | <a class="has-text-link" @click="open_tracks">tracks</a></p>
<list-item-albums v-for="album in genreAlbums.items" :key="album.id" :album="album" :links="links"></list-item-albums> <list-item-albums v-for="album in genreAlbums.items" :key="album.id" :album="album" :links="links">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-albums>
<modal-dialog-album :show="show_details_modal" :album="selected_album" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -22,6 +29,7 @@ import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import ListItemAlbums from '@/components/ListItemAlbum' import ListItemAlbums from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const genreData = { const genreData = {
@ -52,13 +60,16 @@ const genreData = {
export default { export default {
name: 'PageGenre', name: 'PageGenre',
mixins: [ LoadDataBeforeEnterMixin(genreData) ], mixins: [ LoadDataBeforeEnterMixin(genreData) ],
components: { ContentWithHeading, TabsMusic, ListItemAlbums }, components: { ContentWithHeading, TabsMusic, ListItemAlbums, ModalDialogAlbum },
data () { data () {
return { return {
name: '', name: '',
genreAlbums: {}, genreAlbums: {},
links: [] links: [],
show_details_modal: false,
selected_album: {}
} }
}, },
@ -70,6 +81,11 @@ export default {
play: function () { play: function () {
webapi.player_play_uri(this.genreAlbums.items.map(a => a.uri).join(','), true) webapi.player_play_uri(this.genreAlbums.items.map(a => a.uri).join(','), true)
},
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -11,7 +11,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile"><a class="has-text-link" @click="open_genre">albums</a> | {{ tracks.total }} tracks</p> <p class="heading has-text-centered-mobile"><a class="has-text-link" @click="open_genre">albums</a> | {{ tracks.total }} tracks</p>
<list-item-track v-for="(track, index) in tracks.items" :key="track.id" :track="track" :position="index" :context_uri="tracks.items.map(a => a.uri).join(',')" :links="links"></list-item-track> <list-item-track v-for="(track, index) in tracks.items" :key="track.id" :track="track" :position="index" :context_uri="tracks.items.map(a => a.uri).join(',')" :links="links">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -21,6 +28,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const tracksData = { const tracksData = {
@ -37,13 +45,16 @@ const tracksData = {
export default { export default {
name: 'PageGenreTracks', name: 'PageGenreTracks',
mixins: [ LoadDataBeforeEnterMixin(tracksData) ], mixins: [ LoadDataBeforeEnterMixin(tracksData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
tracks: {}, tracks: {},
genre: '', genre: '',
links: [] links: [],
show_details_modal: false,
selected_track: {}
} }
}, },
@ -55,6 +66,11 @@ export default {
play: function () { play: function () {
webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), true) webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), true)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -11,7 +11,14 @@
<p class="heading">{{ genres.total }} genres</p> <p class="heading">{{ genres.total }} genres</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-genre v-for="(genre, index) in genres.items" :key="genre.name" :genre="genre" :anchor="anchor(genre, index)"></list-item-genre> <list-item-genre v-for="(genre, index) in genres.items" :key="genre.name" :genre="genre" :anchor="anchor(genre, index)">
<template slot="actions">
<a @click="open_dialog(genre)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-genre>
<modal-dialog-genre :show="show_details_modal" :genre="selected_genre" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -23,6 +30,7 @@ import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import IndexButtonList from '@/components/IndexButtonList' import IndexButtonList from '@/components/IndexButtonList'
import ListItemGenre from '@/components/ListItemGenre' import ListItemGenre from '@/components/ListItemGenre'
import ModalDialogGenre from '@/components/ModalDialogGenre'
import webapi from '@/webapi' import webapi from '@/webapi'
const genresData = { const genresData = {
@ -38,11 +46,14 @@ const genresData = {
export default { export default {
name: 'PageGenres', name: 'PageGenres',
mixins: [ LoadDataBeforeEnterMixin(genresData) ], mixins: [ LoadDataBeforeEnterMixin(genresData) ],
components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemGenre }, components: { ContentWithHeading, TabsMusic, IndexButtonList, ListItemGenre, ModalDialogGenre },
data () { data () {
return { return {
genres: { items: [] } genres: { items: [] },
show_details_modal: false,
selected_genre: {}
} }
}, },
@ -56,6 +67,11 @@ export default {
methods: { methods: {
anchor: function (genre, index) { anchor: function (genre, index) {
return genre.name.charAt(0).toUpperCase() return genre.name.charAt(0).toUpperCase()
},
open_dialog: function (genre) {
this.selected_genre = genre
this.show_details_modal = true
} }
} }
} }

View File

@ -10,7 +10,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ tracks.length }} tracks</p> <p class="heading has-text-centered-mobile">{{ tracks.length }} tracks</p>
<list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="playlist.uri"></list-item-track> <list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="playlist.uri">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -19,6 +26,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const playlistData = { const playlistData = {
@ -38,18 +46,26 @@ const playlistData = {
export default { export default {
name: 'PagePlaylist', name: 'PagePlaylist',
mixins: [ LoadDataBeforeEnterMixin(playlistData) ], mixins: [ LoadDataBeforeEnterMixin(playlistData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
playlist: {}, playlist: {},
tracks: [] tracks: [],
show_details_modal: false,
selected_track: {}
} }
}, },
methods: { methods: {
play: function () { play: function () {
webapi.player_play_uri(this.playlist.uri, true) webapi.player_play_uri(this.playlist.uri, true)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -5,7 +5,14 @@
<p class="heading">{{ playlists.total }} playlists</p> <p class="heading">{{ playlists.total }} playlists</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist"></list-item-playlist> <list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist">
<template slot="actions">
<a @click="open_dialog(playlist)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-playlist>
<modal-dialog-playlist :show="show_details_modal" :playlist="selected_playlist" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -15,6 +22,7 @@ import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import TabsMusic from '@/components/TabsMusic' import TabsMusic from '@/components/TabsMusic'
import ListItemPlaylist from '@/components/ListItemPlaylist' import ListItemPlaylist from '@/components/ListItemPlaylist'
import ModalDialogPlaylist from '@/components/ModalDialogPlaylist'
import webapi from '@/webapi' import webapi from '@/webapi'
const playlistsData = { const playlistsData = {
@ -30,11 +38,21 @@ const playlistsData = {
export default { export default {
name: 'PagePlaylists', name: 'PagePlaylists',
mixins: [ LoadDataBeforeEnterMixin(playlistsData) ], mixins: [ LoadDataBeforeEnterMixin(playlistsData) ],
components: { ContentWithHeading, TabsMusic, ListItemPlaylist }, components: { ContentWithHeading, TabsMusic, ListItemPlaylist, ModalDialogPlaylist },
data () { data () {
return { return {
playlists: {} playlists: {},
show_details_modal: false,
selected_playlist: {}
}
},
methods: {
open_dialog: function (playlist) {
this.selected_playlist = playlist
this.show_details_modal = true
} }
} }
} }

View File

@ -13,7 +13,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p> <p class="heading has-text-centered-mobile">{{ album.track_count }} tracks</p>
<list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri"></list-item-track> <list-item-track v-for="(track, index) in tracks" :key="track.id" :track="track" :position="index" :context_uri="album.uri">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -22,6 +29,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const albumData = { const albumData = {
@ -41,18 +49,26 @@ const albumData = {
export default { export default {
name: 'PagePodcast', name: 'PagePodcast',
mixins: [ LoadDataBeforeEnterMixin(albumData) ], mixins: [ LoadDataBeforeEnterMixin(albumData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
album: {}, album: {},
tracks: [] tracks: [],
show_details_modal: false,
selected_track: {}
} }
}, },
methods: { methods: {
play: function () { play: function () {
webapi.player_play_uri(this.album.uri, false) webapi.player_play_uri(this.album.uri, false)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }

View File

@ -6,7 +6,14 @@
<p class="heading">{{ albums.total }} podcasts</p> <p class="heading">{{ albums.total }} podcasts</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="album in albums.items" :key="album.id" :album="album" :media_kind="'podcast'"></list-item-album> <list-item-album v-for="album in albums.items" :key="album.id" :album="album" :media_kind="'podcast'">
<template slot="actions">
<a @click="open_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_details_modal" :album="selected_album" :media_kind="'podcast'" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -16,6 +23,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import webapi from '@/webapi' import webapi from '@/webapi'
const albumsData = { const albumsData = {
@ -31,11 +39,21 @@ const albumsData = {
export default { export default {
name: 'PagePodcasts', name: 'PagePodcasts',
mixins: [ LoadDataBeforeEnterMixin(albumsData) ], mixins: [ LoadDataBeforeEnterMixin(albumsData) ],
components: { ContentWithHeading, ListItemAlbum }, components: { ContentWithHeading, ListItemAlbum, ModalDialogAlbum },
data () { data () {
return { return {
albums: {} albums: {},
show_details_modal: false,
selected_album: {}
}
},
methods: {
open_dialog: function (album) {
this.selected_album = album
this.show_details_modal = true
} }
} }
} }

View File

@ -40,8 +40,18 @@
:key="item.id" :item="item" :position="index" :key="item.id" :item="item" :position="index"
:current_position="current_position" :current_position="current_position"
:show_only_next_items="show_only_next_items" :show_only_next_items="show_only_next_items"
:edit_mode="edit_mode"></list-item-queue-item> :edit_mode="edit_mode">
<template slot="actions">
<a @click="open_dialog(item)" v-if="!edit_mode">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
<a @click="remove(item)" v-if="item.id !== state.item_id && edit_mode">
<span class="icon has-text-grey"><i class="mdi mdi-delete mdi-18px"></i></span>
</a>
</template>
</list-item-queue-item>
</draggable> </draggable>
<modal-dialog-queue-item :show="show_details_modal" :item="selected_item" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</template> </template>
@ -49,17 +59,21 @@
<script> <script>
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemQueueItem from '@/components/ListItemQueueItem' import ListItemQueueItem from '@/components/ListItemQueueItem'
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem'
import webapi from '@/webapi' import webapi from '@/webapi'
import * as types from '@/store/mutation_types' import * as types from '@/store/mutation_types'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
export default { export default {
name: 'PageQueue', name: 'PageQueue',
components: { ContentWithHeading, ListItemQueueItem, draggable }, components: { ContentWithHeading, ListItemQueueItem, draggable, ModalDialogQueueItem },
data () { data () {
return { return {
edit_mode: false edit_mode: false,
show_details_modal: false,
selected_item: {}
} }
}, },
@ -92,6 +106,10 @@ export default {
this.$store.commit(types.SHOW_ONLY_NEXT_ITEMS, !this.show_only_next_items) this.$store.commit(types.SHOW_ONLY_NEXT_ITEMS, !this.show_only_next_items)
}, },
remove: function (item) {
webapi.queue_remove(item.id)
},
move_item: function (e) { move_item: function (e) {
var oldPosition = !this.show_only_next_items ? e.oldIndex : e.oldIndex + this.current_position var oldPosition = !this.show_only_next_items ? e.oldIndex : e.oldIndex + this.current_position
var item = this.queue_items[oldPosition] var item = this.queue_items[oldPosition]
@ -99,6 +117,11 @@ export default {
if (newPosition !== oldPosition) { if (newPosition !== oldPosition) {
webapi.queue_move(item.id, newPosition) webapi.queue_move(item.id, newPosition)
} }
},
open_dialog: function (item) {
this.selected_item = item
this.show_details_modal = true
} }
} }
} }

View File

@ -31,7 +31,14 @@
<p class="title is-4">Tracks</p> <p class="title is-4">Tracks</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-track v-for="track in tracks.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri"></list-item-track> <list-item-track v-for="track in tracks.items" :key="track.id" :track="track" :position="0" :context_uri="track.uri">
<template slot="actions">
<a @click="open_track_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_track_details_modal" :track="selected_track" @close="show_track_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav v-if="show_all_tracks_button" class="level"> <nav v-if="show_all_tracks_button" class="level">
@ -49,7 +56,14 @@
<p class="title is-4">Artists</p> <p class="title is-4">Artists</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-artist v-for="artist in artists.items" :key="artist.id" :artist="artist"></list-item-artist> <list-item-artist v-for="artist in artists.items" :key="artist.id" :artist="artist">
<template slot="actions">
<a @click="open_artist_dialog(artist)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-artist>
<modal-dialog-artist :show="show_artist_details_modal" :artist="selected_artist" @close="show_artist_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav v-if="show_all_artists_button" class="level"> <nav v-if="show_all_artists_button" class="level">
@ -67,7 +81,14 @@
<p class="title is-4">Albums</p> <p class="title is-4">Albums</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-album v-for="album in albums.items" :key="album.id" :album="album"></list-item-album> <list-item-album v-for="album in albums.items" :key="album.id" :album="album">
<template slot="actions">
<a @click="open_album_dialog(album)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-album>
<modal-dialog-album :show="show_album_details_modal" :album="selected_album" @close="show_album_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav v-if="show_all_albums_button" class="level"> <nav v-if="show_all_albums_button" class="level">
@ -85,7 +106,14 @@
<p class="title is-4">Playlists</p> <p class="title is-4">Playlists</p>
</template> </template>
<template slot="content"> <template slot="content">
<list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist"></list-item-playlist> <list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist">
<template slot="actions">
<a @click="open_playlist_dialog(playlist)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-playlist>
<modal-dialog-playlist :show="show_playlist_details_modal" :playlist="selected_playlist" @close="show_playlist_details_modal = false" />
</template> </template>
<template slot="footer"> <template slot="footer">
<nav v-if="show_all_playlists_button" class="level"> <nav v-if="show_all_playlists_button" class="level">
@ -106,12 +134,16 @@ import ListItemTrack from '@/components/ListItemTrack'
import ListItemArtist from '@/components/ListItemArtist' import ListItemArtist from '@/components/ListItemArtist'
import ListItemAlbum from '@/components/ListItemAlbum' import ListItemAlbum from '@/components/ListItemAlbum'
import ListItemPlaylist from '@/components/ListItemPlaylist' import ListItemPlaylist from '@/components/ListItemPlaylist'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import ModalDialogAlbum from '@/components/ModalDialogAlbum'
import ModalDialogArtist from '@/components/ModalDialogArtist'
import ModalDialogPlaylist from '@/components/ModalDialogPlaylist'
import webapi from '@/webapi' import webapi from '@/webapi'
import * as types from '@/store/mutation_types' import * as types from '@/store/mutation_types'
export default { export default {
name: 'PageSearch', name: 'PageSearch',
components: { ContentWithHeading, TabsSearch, ListItemTrack, ListItemArtist, ListItemAlbum, ListItemPlaylist }, components: { ContentWithHeading, TabsSearch, ListItemTrack, ListItemArtist, ListItemAlbum, ListItemPlaylist, ModalDialogTrack, ModalDialogAlbum, ModalDialogArtist, ModalDialogPlaylist },
data () { data () {
return { return {
@ -119,7 +151,19 @@ export default {
tracks: { items: [], total: 0 }, tracks: { items: [], total: 0 },
artists: { items: [], total: 0 }, artists: { items: [], total: 0 },
albums: { items: [], total: 0 }, albums: { items: [], total: 0 },
playlists: { items: [], total: 0 } playlists: { items: [], total: 0 },
show_track_details_modal: false,
selected_track: {},
show_album_details_modal: false,
selected_album: {},
show_artist_details_modal: false,
selected_artist: {},
show_playlist_details_modal: false,
selected_playlist: {}
} }
}, },
@ -241,6 +285,26 @@ export default {
open_recent_search: function (query) { open_recent_search: function (query) {
this.search_query = query this.search_query = query
this.new_search() this.new_search()
},
open_track_dialog: function (track) {
this.selected_track = track
this.show_track_details_modal = true
},
open_album_dialog: function (album) {
this.selected_album = album
this.show_album_details_modal = true
},
open_artist_dialog: function (artist) {
this.selected_artist = artist
this.show_artist_details_modal = true
},
open_playlist_dialog: function (playlist) {
this.selected_playlist = playlist
this.show_playlist_details_modal = true
} }
}, },

View File

@ -11,7 +11,14 @@
</template> </template>
<template slot="content"> <template slot="content">
<p class="heading has-text-centered-mobile"><a class="has-text-link" @click="open_artist">{{ artist.album_count }} albums</a> | {{ artist.track_count }} tracks</p> <p class="heading has-text-centered-mobile"><a class="has-text-link" @click="open_artist">{{ artist.album_count }} albums</a> | {{ artist.track_count }} tracks</p>
<list-item-track v-for="(track, index) in tracks.items" :key="track.id" :track="track" :position="index" :context_uri="tracks.items.map(a => a.uri).join(',')"></list-item-track> <list-item-track v-for="(track, index) in tracks.items" :key="track.id" :track="track" :position="index" :context_uri="tracks.items.map(a => a.uri).join(',')">
<template slot="actions">
<a @click="open_dialog(track)">
<span class="icon has-text-dark"><i class="mdi mdi-dots-vertical mdi-18px"></i></span>
</a>
</template>
</list-item-track>
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" />
</template> </template>
</content-with-heading> </content-with-heading>
</div> </div>
@ -21,6 +28,7 @@
import { LoadDataBeforeEnterMixin } from './mixin' import { LoadDataBeforeEnterMixin } from './mixin'
import ContentWithHeading from '@/templates/ContentWithHeading' import ContentWithHeading from '@/templates/ContentWithHeading'
import ListItemTrack from '@/components/ListItemTrack' import ListItemTrack from '@/components/ListItemTrack'
import ModalDialogTrack from '@/components/ModalDialogTrack'
import webapi from '@/webapi' import webapi from '@/webapi'
const tracksData = { const tracksData = {
@ -40,12 +48,15 @@ const tracksData = {
export default { export default {
name: 'PageTracks', name: 'PageTracks',
mixins: [ LoadDataBeforeEnterMixin(tracksData) ], mixins: [ LoadDataBeforeEnterMixin(tracksData) ],
components: { ContentWithHeading, ListItemTrack }, components: { ContentWithHeading, ListItemTrack, ModalDialogTrack },
data () { data () {
return { return {
artist: {}, artist: {},
tracks: {} tracks: {},
show_details_modal: false,
selected_track: {}
} }
}, },
@ -57,6 +68,11 @@ export default {
play: function () { play: function () {
webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), true) webapi.player_play_uri(this.tracks.items.map(a => a.uri).join(','), true)
},
open_dialog: function (track) {
this.selected_track = track
this.show_details_modal = true
} }
} }
} }