[web] Refactor modal dialogs

This commit is contained in:
Alain Nussbaumer 2025-02-09 17:52:45 +01:00
parent b9b36855f4
commit e3c8d1fab9
25 changed files with 453 additions and 639 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -44,14 +44,12 @@ export default {
items: { required: true, type: Object }, items: { required: true, type: Object },
media_kind: { required: true, type: String } media_kind: { required: true, type: String }
}, },
data() { data() {
return { return {
selected_item: {}, selected_item: {},
show_details_modal: false show_details_modal: false
} }
}, },
methods: { methods: {
open(item) { open(item) {
this.$router.push({ this.$router.push({

View File

@ -11,7 +11,7 @@
<footer v-if="actions.length" class="card-footer"> <footer v-if="actions.length" class="card-footer">
<a <a
v-for="action in actions" v-for="action in actions"
:key="action.event" :key="action.label"
class="card-footer-item" class="card-footer-item"
:class="{ 'is-disabled': action.disabled }" :class="{ 'is-disabled': action.disabled }"
@click="action.handler" @click="action.handler"

View File

@ -1,7 +1,11 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog
:actions="actions"
:show="show"
:title="$t('dialog.add.rss.title')"
@close="$emit('close')"
>
<template #content> <template #content>
<p class="title is-4" v-text="$t('dialog.add.rss.title')" />
<div class="field"> <div class="field">
<p class="control has-icons-left"> <p class="control has-icons-left">
<input <input

View File

@ -1,8 +1,12 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog
:actions="actions"
:show="show"
:title="$t('dialog.add.stream.title')"
@close="$emit('close')"
>
<template #content> <template #content>
<form @submit.prevent="play"> <form @submit.prevent="play">
<p class="title is-4" v-text="$t('dialog.add.stream.title')" />
<div class="field"> <div class="field">
<p class="control has-icons-left"> <p class="control has-icons-left">
<input <input

View File

@ -1,107 +1,78 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<cover-artwork
:url="item.artwork_url"
:artist="item.artist"
:album="item.name"
class="is-normal mb-3"
/>
<div v-if="media_kind_resolved === 'podcast'" class="buttons">
<a
class="button is-small"
@click="mark_played"
v-text="$t('dialog.album.mark-as-played')"
/>
<a
v-if="item.data_kind === 'url'"
class="button is-small"
@click="$emit('remove-podcast')"
v-text="$t('dialog.album.remove-podcast')"
/>
</div>
<div v-if="item.artist" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.album.artist')"
/>
<div class="title is-6">
<a @click="open_artist" v-text="item.artist" />
</div>
</div>
<div v-if="item.date_released" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.album.release-date')"
/>
<div class="title is-6" v-text="$filters.date(item.date_released)" />
</div>
<div v-else-if="item.year" class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.album.year')" />
<div class="title is-6" v-text="item.year" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.album.tracks')"
/>
<div class="title is-6" v-text="item.track_count" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.album.duration')"
/>
<div
class="title is-6"
v-text="$filters.durationInHours(item.length_ms)"
/>
</div>
<div class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.album.type')" />
<div
class="title is-6"
v-text="
`${$t(`media.kind.${item.media_kind}`)} - ${$t(`data.kind.${item.data_kind}`)}`
"
/>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.album.added-on')"
/>
<div class="title is-6" v-text="$filters.datetime(item.time_added)" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
import CoverArtwork from '@/components/CoverArtwork.vue'
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue' import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
import webapi from '@/webapi' import webapi from '@/webapi'
export default { export default {
name: 'ModalDialogAlbum', name: 'ModalDialogAlbum',
components: { ModalDialogPlayable, CoverArtwork }, components: { ModalDialogPlayable },
props: { props: {
item: { required: true, type: Object }, item: { required: true, type: Object },
media_kind: { default: '', type: String }, media_kind: { default: '', type: String },
show: Boolean show: Boolean
}, },
emits: ['close', 'remove-podcast', 'play-count-changed'], emits: ['close', 'remove-podcast', 'play-count-changed'],
data() {
return {
artwork_visible: false
}
},
computed: { computed: {
buttons() {
if (this.media_kind_resolved === 'podcast') {
if (item.data_kind === 'url') {
return [
{ label: 'dialog.album.mark-as-played', action: this.mark_played },
{
label: 'dialog.album.remove-podcast',
action: this.remove_podcast
}
]
}
return [
{ label: 'dialog.album.mark-as-played', action: this.mark_played }
]
}
return []
},
media_kind_resolved() { media_kind_resolved() {
return this.media_kind || this.item.media_kind return this.media_kind || this.item.media_kind
},
playable() {
return {
name: this.item.name,
action: this.open,
image: this.item.artwork_url,
artist: this.item.artist,
album: this.item.name,
properties: [
{
label: 'dialog.album.artist',
value: this.item.artist,
action: this.open_artist
},
{
label: 'dialog.album.release-date',
value: this.$filters.date(this.item.date_released)
},
{ label: 'dialog.album.year', value: this.item.year },
{ label: 'dialog.album.tracks', value: this.item.track_count },
{
label: 'dialog.album.duration',
value: this.$filters.durationInHours(this.item.length_ms)
},
{
label: 'dialog.album.type',
value: `${this.$t(`media.kind.${this.item.media_kind}`)} - ${this.$t(`data.kind.${this.item.data_kind}`)}`
},
{
label: 'dialog.album.added-on',
value: this.$filters.datetime(this.item.time_added)
}
]
}
} }
}, },
methods: { methods: {
@ -142,6 +113,9 @@ export default {
params: { id: this.item.artist_id } params: { id: this.item.artist_id }
}) })
} }
},
remove_podcast() {
this.$emit('remove-podcast')
} }
} }
} }

View File

@ -1,55 +1,46 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<cover-artwork
:url="artwork_url(item)"
:artist="item.artist"
:album="item.name"
class="is-normal mb-3"
/>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.album.album-artist')"
/>
<div class="title is-6">
<a @click="open_artist" v-text="item.artists[0].name" />
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.album.release-date')"
/>
<div class="title is-6" v-text="$filters.date(item.release_date)" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.album.type')"
/>
<div class="title is-6" v-text="item.album_type" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
import CoverArtwork from '@/components/CoverArtwork.vue'
import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue' import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
export default { export default {
name: 'ModalDialogAlbumSpotify', name: 'ModalDialogAlbumSpotify',
components: { ModalDialogPlayable, CoverArtwork }, components: { ModalDialogPlayable },
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: {
playable() {
return {
name: this.item.name || '',
image: this.item?.images?.[0]?.url || '',
artist: this.item.artist || '',
album: this.item.name || '',
action: this.open,
properties: [
{
label: 'dialog.spotify.album.album-artist',
value: this.item?.artists?.[0]?.name,
action: this.open_artist
},
{
label: 'dialog.spotify.album.release-date',
value: this.$filters.date(this.item.release_date)
},
{
label: 'dialog.spotify.album.type',
value: this.item.album_type
}
]
}
}
},
methods: { methods: {
artwork_url(item) {
return item.images?.[0]?.url || ''
},
open() { open() {
this.$emit('close') this.$emit('close')
this.$router.push({ this.$router.push({

View File

@ -1,36 +1,9 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.artist.albums')"
/>
<div class="title is-6" v-text="item.album_count" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.artist.tracks')"
/>
<div class="title is-6" v-text="item.track_count" />
</div>
<div class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.artist.type')" />
<div class="title is-6" v-text="$t(`data.kind.${item.data_kind}`)" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.artist.added-on')"
/>
<div class="title is-6" v-text="$filters.datetime(item.time_added)" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -41,6 +14,26 @@ export default {
components: { ModalDialogPlayable }, components: { ModalDialogPlayable },
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: {
playable() {
return {
name: this.item.name,
action: this.open,
properties: [
{ label: 'dialog.artist.albums', value: this.item.album_count },
{ label: 'dialog.artist.tracks', value: this.item.track_count },
{
label: 'dialog.artist.type',
value: this.$t(`data.kind.${this.item.data_kind}`)
},
{
label: 'dialog.artist.added-on',
value: this.$filters.datetime(this.item.time_added)
}
]
}
}
},
methods: { methods: {
open() { open() {
this.$emit('close') this.$emit('close')

View File

@ -1,28 +1,9 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.artist.popularity')"
/>
<div
class="title is-6"
v-text="[item.popularity, item.followers.total].join(' / ')"
/>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.artist.genres')"
/>
<div class="title is-6" v-text="item.genres.join(', ')" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -33,6 +14,26 @@ export default {
components: { ModalDialogPlayable }, components: { ModalDialogPlayable },
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: {
playable() {
return {
name: this.item.name,
action: this.open,
properties: [
{
label: 'dialog.spotify.artist.popularity',
value: [this.item.popularity, this.item.followers?.total].join(
' / '
)
},
{
label: 'dialog.spotify.artist.genres',
value: this.item.genres?.join(', ')
}
]
}
}
},
methods: { methods: {
open() { open() {
this.$emit('close') this.$emit('close')

View File

@ -1,43 +1,9 @@
<template> <template>
<modal-dialog-playable <modal-dialog-playable
:expression="expression" :item="playable"
:show="show" :show="show"
@close="$emit('close')" @close="$emit('close')"
> />
<template #content>
<div class="title is-4">
<a @click="open_albums" v-text="item.name" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.composer.albums')"
/>
<div class="title is-6">
<a @click="open_albums" v-text="item.album_count" />
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.composer.tracks')"
/>
<div class="title is-6">
<a @click="open_tracks" v-text="item.track_count" />
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.composer.duration')"
/>
<div
class="title is-6"
v-text="$filters.durationInHours(item.length_ms)"
/>
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -49,8 +15,28 @@ export default {
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: { computed: {
expression() { playable() {
return `composer is "${this.item.name}" and media_kind is music` return {
action: this.open_albums,
name: this.item.name,
expression: `composer is "${this.item.name}" and media_kind is music`,
properties: [
{
label: 'dialog.composer.albums',
value: this.item.album_count,
action: this.open_albums
},
{
label: 'dialog.composer.tracks',
value: this.item.track_count,
action: this.open_tracks
},
{
label: 'dialog.composer.duration',
value: this.$filters.durationInHours(this.item.length_ms)
}
]
}
} }
}, },
methods: { methods: {

View File

@ -1,8 +1,7 @@
<template> <template>
<modal-dialog-playable <modal-dialog-playable
:expression="expression" :item="playable"
:show="show" :show="show"
:title="item"
@close="$emit('close')" @close="$emit('close')"
/> />
</template> </template>
@ -16,8 +15,11 @@ export default {
props: { item: { required: true, type: String }, show: Boolean }, props: { item: { required: true, type: String }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: { computed: {
expression() { playable() {
return `path starts with "${this.item}" order by path asc` return {
name: this.item,
expression: `path starts with "${this.item}" order by path asc`
}
} }
} }
} }

View File

@ -1,39 +1,9 @@
<template> <template>
<modal-dialog-playable <modal-dialog-playable
:expression="expression" :item="playable"
:show="show" :show="show"
@close="$emit('close')" @close="$emit('close')"
> />
<template #content>
<div class="title is-4">
<a @click="open" v-text="item.name" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.genre.albums')"
/>
<div class="title is-6" v-text="item.album_count" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.genre.tracks')"
/>
<div class="title is-6" v-text="item.track_count" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.genre.duration')"
/>
<div
class="title is-6"
v-text="$filters.durationInHours(item.length_ms)"
/>
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -49,8 +19,26 @@ export default {
}, },
emits: ['close'], emits: ['close'],
computed: { computed: {
expression() { playable() {
return `genre is "${this.item.name}" and media_kind is ${this.media_kind}` return {
name: this.item.name,
action: this.open,
expression: `genre is "${this.item.name}" and media_kind is ${this.media_kind}`,
properties: [
{
label: 'dialog.genre.albums',
value: this.item.album_count
},
{
label: 'dialog.genre.tracks',
value: this.item.track_count
},
{
label: 'dialog.genre.duration',
value: this.$filters.durationInHours(this.item.length_ms)
}
]
}
} }
}, },
methods: { methods: {

View File

@ -1,26 +1,50 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog :actions="actions" :show="show" @close="$emit('close')">
<template #content> <template #content>
<slot name="content" /> <div class="title is-4">
<a v-if="item.action" @click="item.action" v-text="item.name"></a>
<span v-else v-text="item.name" />
</div>
<cover-artwork
v-if="item.image"
:url="item.image"
:artist="item.artist"
:album="item.name"
class="is-normal mb-3"
/>
<div v-for="button in buttons" :key="button.label" class="buttons">
<a v-t="button.label" class="button is-small" @click="button.action" />
</div>
<div
v-for="property in item.properties?.filter((p) => p.value)"
:key="property.label"
class="mb-3"
>
<div v-t="property.label" class="is-size-7 is-uppercase" />
<div class="title is-6">
<a
v-if="property.action"
@click="property.action"
v-text="property.value"
/>
<span v-else class="title is-6" v-text="property.value" />
</div>
</div>
</template> </template>
</modal-dialog> </modal-dialog>
</template> </template>
<script> <script>
import CoverArtwork from '@/components/CoverArtwork.vue'
import ModalDialog from '@/components/ModalDialog.vue' import ModalDialog from '@/components/ModalDialog.vue'
import webapi from '@/webapi' import webapi from '@/webapi'
export default { export default {
name: 'ModalDialogPlayable', name: 'ModalDialogPlayable',
components: { ModalDialog }, components: { ModalDialog, CoverArtwork },
props: { props: {
expression: { default: '', type: String }, buttons: { default: () => [], type: Array },
item: { item: { required: true, type: Object },
default() {
return {}
},
type: Object
},
show: Boolean show: Boolean
}, },
emits: ['close'], emits: ['close'],
@ -48,26 +72,26 @@ export default {
methods: { methods: {
play() { play() {
this.$emit('close') this.$emit('close')
if (this.expression) { if (this.item.expression) {
webapi.player_play_expression(this.expression, false) webapi.player_play_expression(this.item.expression, false)
} else { } else {
webapi.player_play_uri(this.item.uri, false) webapi.player_play_uri(this.item.uris || this.item.item.uri, false)
} }
}, },
queue_add() { queue_add() {
this.$emit('close') this.$emit('close')
if (this.expression) { if (this.item.expression) {
webapi.queue_expression_add(this.expression) webapi.queue_expression_add(this.item.expression)
} else { } else {
webapi.queue_add(this.item.uri) webapi.queue_add(this.item.uris || this.item.uri)
} }
}, },
queue_add_next() { queue_add_next() {
this.$emit('close') this.$emit('close')
if (this.expression) { if (this.item.expression) {
webapi.queue_expression_add_next(this.expression) webapi.queue_expression_add_next(this.item.expression)
} else { } else {
webapi.queue_add_next(this.item.uri) webapi.queue_add_next(this.item.uris || this.item.uri)
} }
} }
} }

View File

@ -1,41 +1,17 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.playlist.path')"
/>
<div class="title is-6" v-text="item.path" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.playlist.type')"
/>
<div class="title is-6" v-text="$t(`playlist.type.${item.type}`)" />
</div>
<div v-if="!item.folder" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.playlist.tracks')"
/>
<div class="title is-6" v-text="item.item_count" />
</div>
</template>
</modal-dialog>
</template> </template>
<script> <script>
import ModalDialog from '@/components/ModalDialog.vue' import ModalDialogPlayable from '@/components/ModalDialogPlayable.vue'
import webapi from '@/webapi'
export default { export default {
name: 'ModalDialogPlaylist', name: 'ModalDialogPlaylist',
components: { ModalDialog }, components: { ModalDialogPlayable },
props: { props: {
item: { required: true, type: Object }, item: { required: true, type: Object },
show: Boolean, show: Boolean,
@ -43,27 +19,20 @@ export default {
}, },
emits: ['close'], emits: ['close'],
computed: { computed: {
actions() { playable() {
if (!this.item.folder) { return {
return [ name: this.item.name,
action: this.open,
uris: this.uris,
properties: [
{ label: 'dialog.playlist.tracks', value: this.item.item_count },
{ {
label: this.$t('dialog.playlist.add'), label: 'dialog.playlist.type',
handler: this.queue_add, value: this.$t(`playlist.type.${this.item.type}`)
icon: 'playlist-plus'
}, },
{ { label: 'dialog.playlist.path', value: this.item.path }
label: this.$t('dialog.playlist.add-next'),
handler: this.queue_add_next,
icon: 'playlist-play'
},
{
label: this.$t('dialog.playlist.play'),
handler: this.play,
icon: 'play'
}
] ]
} }
return []
} }
}, },
methods: { methods: {
@ -73,18 +42,6 @@ export default {
name: 'playlist', name: 'playlist',
params: { id: this.item.id } params: { id: this.item.id }
}) })
},
play() {
this.$emit('close')
webapi.player_play_uri(this.uris || this.item.uri, false)
},
queue_add() {
this.$emit('close')
webapi.queue_add(this.uris || this.item.uri)
},
queue_add_next() {
this.$emit('close')
webapi.queue_add_next(this.uris || this.item.uri)
} }
} }
} }

View File

@ -1,8 +1,12 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog
:actions="actions"
:show="show"
:title="$t('dialog.playlist.save.title')"
@close="$emit('close')"
>
<template #content> <template #content>
<form @submit.prevent="save"> <form @submit.prevent="save">
<p class="title is-4" v-text="$t('dialog.playlist.save.title')" />
<div class="field"> <div class="field">
<p class="control has-icons-left"> <p class="control has-icons-left">
<input <input

View File

@ -1,32 +1,9 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<div class="title is-4"> :show="show"
<a @click="open" v-text="item.name" /> @close="$emit('close')"
</div> />
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.playlist.owner')"
/>
<div class="title is-6" v-text="item.owner.display_name" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.playlist.tracks')"
/>
<div class="title is-6" v-text="item.tracks.total" />
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.playlist.path')"
/>
<div class="title is-6" v-text="item.uri" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -37,6 +14,25 @@ export default {
components: { ModalDialogPlayable }, components: { ModalDialogPlayable },
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: {
playable() {
return {
name: this.item.name,
action: this.open,
properties: [
{
label: 'dialog.spotify.playlist.owner',
value: this.item.owner?.display_name
},
{
label: 'dialog.spotify.playlist.tracks',
value: this.item.tracks?.total
},
{ label: 'dialog.spotify.playlist.path', value: this.item.uri }
]
}
}
},
methods: { methods: {
open() { open() {
this.$emit('close') this.$emit('close')

View File

@ -1,7 +1,11 @@
<template> <template>
<modal-dialog :actions="actions" :show="show" @close="$emit('close')"> <modal-dialog
:actions="actions"
:show="show"
:title="$t('dialog.remote-pairing.title')"
@close="$emit('close')"
>
<template #content> <template #content>
<p class="title is-4" v-text="$t('dialog.remote-pairing.title')" />
<form @submit.prevent="pair"> <form @submit.prevent="pair">
<label class="label" v-text="pairing.remote" /> <label class="label" v-text="pairing.remote" />
<div class="field"> <div class="field">

View File

@ -1,156 +1,9 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<p class="title is-4" v-text="item.title" /> :show="show"
<p class="subtitle" v-text="item.artist" /> @close="$emit('close')"
<div v-if="item.media_kind === 'podcast'" class="buttons"> />
<a
v-if="item.play_count > 0"
class="button is-small"
@click="mark_new"
v-text="$t('dialog.track.mark-as-new')"
/>
<a
v-if="item.play_count === 0"
class="button is-small"
@click="mark_played"
v-text="$t('dialog.track.mark-as-played')"
/>
</div>
<div v-if="item.album" class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.track.album')" />
<div class="title is-6">
<a @click="open_album" v-text="item.album" />
</div>
</div>
<div
v-if="item.album_artist && item.media_kind !== 'audiobook'"
class="mb-3"
>
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.album-artist')"
/>
<div class="title is-6">
<a @click="open_album_artist" v-text="item.album_artist" />
</div>
</div>
<div v-if="item.composer" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.composer')"
/>
<div class="title is-6" v-text="item.composer" />
</div>
<div v-if="item.date_released" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.release-date')"
/>
<div class="title is-6" v-text="$filters.date(item.date_released)" />
</div>
<div v-else-if="item.year" class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.track.year')" />
<div class="title is-6" v-text="item.year" />
</div>
<div v-if="item.genre" class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.track.genre')" />
<div class="title is-6">
<a @click="open_genre" v-text="item.genre" />
</div>
</div>
<div v-if="item.disc_number" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.position')"
/>
<div
class="title is-6"
v-text="[item.disc_number, item.track_number].join(' / ')"
/>
</div>
<div v-if="item.length_ms" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.duration')"
/>
<div
class="title is-6"
v-text="$filters.durationInHours(item.length_ms)"
/>
</div>
<div class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.track.path')" />
<div class="title is-6" v-text="item.path" />
</div>
<div class="mb-3">
<div class="is-size-7 is-uppercase" v-text="$t('dialog.track.type')" />
<div
class="title is-6"
v-text="
`${$t(`media.kind.${item.media_kind}`)} - ${$t(`data.kind.${item.data_kind}`)}`
"
/>
</div>
<div v-if="item.samplerate" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.quality')"
/>
<div class="title is-6">
<span v-text="item.type" />
<span
v-if="item.samplerate"
v-text="
$t('dialog.track.samplerate', {
rate: item.samplerate
})
"
/>
<span
v-if="item.channels"
v-text="
$t('dialog.track.channels', {
channels: $filters.channels(item.channels)
})
"
/>
<span
v-if="item.bitrate"
v-text="$t('dialog.track.bitrate', { rate: item.bitrate })"
/>
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.added-on')"
/>
<div class="title is-6" v-text="$filters.datetime(item.time_added)" />
</div>
<div>
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.rating')"
/>
<div
class="title is-6"
v-text="
$t('dialog.track.rating-value', {
rating: Math.floor(item.rating / 10)
})
"
/>
</div>
<div v-if="item.comment" class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.track.comment')"
/>
<div class="title is-6" v-text="item.comment" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -172,6 +25,78 @@ export default {
spotify_track: {} spotify_track: {}
} }
}, },
computed: {
buttons() {
if (this.item.media_kind === 'podcast') {
if (this.item.play_count > 0) {
return [{ label: 'dialog.track.mark-as-new', action: this.mark_new }]
}
if (this.item.play_count === 0) {
return [
{ label: 'dialog.track.mark-as-played', action: this.mark_played }
]
}
}
return []
},
playable() {
return {
name: this.item.title,
properties: [
{
label: 'dialog.track.album',
value: this.item.album,
action: this.open_album
},
{
label: 'dialog.track.album-artist',
value: this.item.album_artist,
action: this.open_artist
},
{ label: 'dialog.track.composer', value: this.item.composer },
{
label: 'dialog.track.release-date',
value: this.$filters.date(this.item.date_released)
},
{ label: 'dialog.track.year', value: this.item.year },
{ label: 'dialog.track.genre', value: this.item.genre },
{
label: 'dialog.track.position',
value: [this.item.disc_number, this.item.track_number].join(' / ')
},
{
label: 'dialog.track.duration',
value: this.$filters.durationInHours(this.item.length_ms)
},
{
label: 'dialog.track.type',
value: `${this.$t(`media.kind.${this.item.media_kind}`)} - ${this.$t(`data.kind.${this.item.data_kind}`)}`
},
{
label: 'dialog.track.quality',
value: this.$t('dialog.track.quality-value', {
format: this.item.type,
bitrate: this.item.bitrate,
channels: this.$filters.channels(this.item.channels),
samplerate: this.item.samplerate
})
},
{
label: 'dialog.track.added-on',
value: this.$filters.datetime(this.item.time_added)
},
{
label: 'dialog.track.rating',
value: this.$t('dialog.track.rating-value', {
rating: Math.floor(this.item.rating / 10)
})
},
{ label: 'dialog.track.comment', value: this.item.comment },
{ label: 'dialog.track.path', value: this.item.path }
]
}
}
},
watch: { watch: {
item() { item() {
if ( if (
@ -234,7 +159,7 @@ export default {
}) })
} }
}, },
open_album_artist() { open_artist() {
if (this.item.data_kind === 'spotify') { if (this.item.data_kind === 'spotify') {
this.$router.push({ this.$router.push({
name: 'music-spotify-artist', name: 'music-spotify-artist',

View File

@ -1,65 +1,9 @@
<template> <template>
<modal-dialog-playable :item="item" :show="show" @close="$emit('close')"> <modal-dialog-playable
<template #content> :item="playable"
<p class="title is-4" v-text="item.name" /> :show="show"
<p class="subtitle" v-text="item.artists[0].name" /> @close="$emit('close')"
<div class="mb-3"> />
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.album')"
/>
<div class="title is-6">
<a @click="open_album" v-text="item.album.name" />
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.album-artist')"
/>
<div class="title is-6">
<a @click="open_artist" v-text="item.artists[0].name" />
</div>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.release-date')"
/>
<div
class="title is-6"
v-text="$filters.date(item.album.release_date)"
/>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.position')"
/>
<div
class="title is-6"
v-text="[item.disc_number, item.track_number].join(' / ')"
/>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.duration')"
/>
<div
class="title is-6"
v-text="$filters.durationInHours(item.duration_ms)"
/>
</div>
<div class="mb-3">
<div
class="is-size-7 is-uppercase"
v-text="$t('dialog.spotify.track.path')"
/>
<div class="title is-6" v-text="item.uri" />
</div>
</template>
</modal-dialog-playable>
</template> </template>
<script> <script>
@ -70,6 +14,39 @@ export default {
components: { ModalDialogPlayable }, components: { ModalDialogPlayable },
props: { item: { required: true, type: Object }, show: Boolean }, props: { item: { required: true, type: Object }, show: Boolean },
emits: ['close'], emits: ['close'],
computed: {
playable() {
return {
name: this.item.name,
subtitle: this.item.artists[0].name,
properties: [
{
label: 'dialog.spotify.track.album',
value: this.item.album.name,
action: this.open_album
},
{
label: 'dialog.spotify.track.album-artist',
value: this.item.artists[0].name,
action: this.open_artist
},
{
label: 'dialog.spotify.track.release-date',
value: this.$filters.date(item.album.release_date)
},
{
label: 'dialog.spotify.track.position',
value: [item.disc_number, item.track_number].join(' / ')
},
{
label: 'dialog.spotify.track.duration',
value: this.$filters.durationInHours(item.duration_ms)
},
{ label: 'dialog.spotify.track.path', value: this.item.uri }
]
}
}
},
methods: { methods: {
open_album() { open_album() {
this.$emit('close') this.$emit('close')

View File

@ -126,8 +126,6 @@
"added-on": "Hinzugefügt am", "added-on": "Hinzugefügt am",
"album-artist": "Album-Künstler", "album-artist": "Album-Künstler",
"album": "Album", "album": "Album",
"bitrate": " {'|'} {rate} Kb/s",
"channels": " {'|'} {channels}",
"comment": "Kommentar", "comment": "Kommentar",
"composer": "Komponist", "composer": "Komponist",
"duration": "Dauer", "duration": "Dauer",
@ -136,11 +134,11 @@
"mark-as-played": "Markiere als gespielt", "mark-as-played": "Markiere als gespielt",
"path": "Pfad", "path": "Pfad",
"position": "Disc / Track", "position": "Disc / Track",
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s",
"quality": "Qualität", "quality": "Qualität",
"rating-value": "{rating} / 10", "rating-value": "{rating} / 10",
"rating": "Bewertung", "rating": "Bewertung",
"release-date": "Erscheinungsdatum", "release-date": "Erscheinungsdatum",
"samplerate": " {'|'} {rate} Hz",
"spotify-album": "Album", "spotify-album": "Album",
"spotify-artist": "Künstler", "spotify-artist": "Künstler",
"type": "Art", "type": "Art",

View File

@ -126,8 +126,6 @@
"added-on": "Added On", "added-on": "Added On",
"album-artist": "Album Artist", "album-artist": "Album Artist",
"album": "Album", "album": "Album",
"bitrate": " {'|'} {rate} kbit/s",
"channels": " {'|'} {channels}",
"comment": "Comment", "comment": "Comment",
"composer": "Composer", "composer": "Composer",
"duration": "Duration", "duration": "Duration",
@ -136,11 +134,11 @@
"mark-as-played": "Mark as played", "mark-as-played": "Mark as played",
"path": "Path", "path": "Path",
"position": "Disc / Track", "position": "Disc / Track",
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s",
"quality": "Quality", "quality": "Quality",
"rating-value": "{rating} / 10", "rating-value": "{rating} / 10",
"rating": "Rating", "rating": "Rating",
"release-date": "Release Date", "release-date": "Release Date",
"samplerate": " {'|'} {rate} Hz",
"spotify-album": "album", "spotify-album": "album",
"spotify-artist": "artist", "spotify-artist": "artist",
"type": "Type", "type": "Type",

View File

@ -126,8 +126,6 @@
"added-on": "Ajouté le", "added-on": "Ajouté le",
"album-artist": "Artiste de lalbum", "album-artist": "Artiste de lalbum",
"album": "Album", "album": "Album",
"bitrate": " {'|'} {rate} kbit/s",
"channels": " {'|'} {channels}",
"comment": "Commentaire", "comment": "Commentaire",
"composer": "Compositeur", "composer": "Compositeur",
"duration": "Durée", "duration": "Durée",
@ -136,11 +134,11 @@
"mark-as-played": "Marquer comme lu", "mark-as-played": "Marquer comme lu",
"path": "Emplacement", "path": "Emplacement",
"position": "Disque / Piste", "position": "Disque / Piste",
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s",
"quality": "Qualité", "quality": "Qualité",
"rating-value": "{rating} / 10", "rating-value": "{rating} / 10",
"rating": "Classement", "rating": "Classement",
"release-date": "Date de sortie", "release-date": "Date de sortie",
"samplerate": " {'|'} {rate} Hz",
"spotify-album": "album", "spotify-album": "album",
"spotify-artist": "artiste", "spotify-artist": "artiste",
"type": "Type", "type": "Type",

View File

@ -126,8 +126,6 @@
"added-on": "添加时间", "added-on": "添加时间",
"album-artist": "专辑艺人", "album-artist": "专辑艺人",
"album": "专辑", "album": "专辑",
"bitrate": " {'|'} {rate} kbit/s",
"channels": " {'|'} {channels}",
"comment": "评论", "comment": "评论",
"composer": "作曲家", "composer": "作曲家",
"duration": "时长", "duration": "时长",
@ -136,11 +134,11 @@
"mark-as-played": "标记为已播放", "mark-as-played": "标记为已播放",
"path": "路径", "path": "路径",
"position": "盘符 / 曲目", "position": "盘符 / 曲目",
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s",
"quality": "质量", "quality": "质量",
"rating-value": "{rating} / 10", "rating-value": "{rating} / 10",
"rating": "评级", "rating": "评级",
"release-date": "发行日期", "release-date": "发行日期",
"samplerate": " {'|'} {rate} Hz",
"spotify-album": "专辑", "spotify-album": "专辑",
"spotify-artist": "艺人", "spotify-artist": "艺人",
"type": "类型", "type": "类型",

View File

@ -126,8 +126,6 @@
"added-on": "新增時間", "added-on": "新增時間",
"album-artist": "專輯藝人", "album-artist": "專輯藝人",
"album": "專輯", "album": "專輯",
"bitrate": " {'|'} {rate} kbit/s",
"channels": " {'|'} {channels}",
"comment": "評論", "comment": "評論",
"composer": "作曲家", "composer": "作曲家",
"duration": "時長", "duration": "時長",
@ -136,11 +134,11 @@
"mark-as-played": "標記為已播放", "mark-as-played": "標記為已播放",
"path": "路徑", "path": "路徑",
"position": "盤符 / 曲目", "position": "盤符 / 曲目",
"quality-value": "{format} {'|'} {samplerate} Hz {'|'} {channels} {'|'} {bitrate} kbit/s",
"quality": "品質", "quality": "品質",
"rating-value": "{rating} / 10", "rating-value": "{rating} / 10",
"rating": "評級", "rating": "評級",
"release-date": "發行日期", "release-date": "發行日期",
"samplerate": " {'|'} {rate} Hz",
"spotify-album": "專輯", "spotify-album": "專輯",
"spotify-artist": "藝人", "spotify-artist": "藝人",
"type": "類型", "type": "類型",