Make playing tracks in their playlist the default
This commit is contained in:
parent
5d745fea6f
commit
f1f9f935cf
|
@ -0,0 +1 @@
|
||||||
|
Make "play in list" the default when interacting with individual tracks (#1274)
|
|
@ -1,14 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="album-entries">
|
<div class="album-entries">
|
||||||
<div :class="[{active: currentTrack && isPlaying && track.id === currentTrack.id}, 'album-entry']" v-for="track in tracks" :key="track.id">
|
<div :class="[{active: currentTrack && isPlaying && track.id === currentTrack.id}, 'album-entry']" @click.prevent="replacePlay(tracks, index)" v-for="(track, index) in tracks" :key="track.id">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<play-button class="basic circular icon" :button-classes="['circular inverted vibrant icon button']" :discrete="true" :icon-only="true" :track="track"></play-button>
|
<play-button class="basic circular icon" :button-classes="['circular inverted vibrant icon button']" :discrete="true" :icon-only="true" :track="track" :tracks="tracks"></play-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="position">{{ prettyPosition(track.position) }}</div>
|
<div class="position">{{ prettyPosition(track.position) }}</div>
|
||||||
<div class="content ellipsis">
|
<div class="content ellipsis">
|
||||||
<router-link :to="{name: 'library.tracks.detail', params: {id: track.id}}" class="discrete link">
|
<strong>{{ track.title }}</strong><br>
|
||||||
<strong>{{ track.title }}</strong><br>
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<template v-if="$store.state.auth.authenticated && $store.getters['favorites/isFavorite'](track.id)">
|
<template v-if="$store.state.auth.authenticated && $store.getters['favorites/isFavorite'](track.id)">
|
||||||
|
@ -17,7 +15,7 @@
|
||||||
<human-duration v-if="track.uploads[0] && track.uploads[0].duration" :duration="track.uploads[0].duration"></human-duration>
|
<human-duration v-if="track.uploads[0] && track.uploads[0].duration" :duration="track.uploads[0].duration"></human-duration>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<play-button class="play-button basic icon" :dropdown-only="true" :is-playable="track.is_playable" :dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']" :track="track"></play-button>
|
<play-button class="play-button basic icon" :dropdown-only="true" :is-playable="track.is_playable" :dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']" :track="track"></play-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,7 +52,13 @@ export default {
|
||||||
var s = String(position);
|
var s = String(position);
|
||||||
while (s.length < (size || 2)) {s = "0" + s;}
|
while (s.length < (size || 2)) {s = "0" + s;}
|
||||||
return s;
|
return s;
|
||||||
}
|
},
|
||||||
|
replacePlay (tracks, trackIndex) {
|
||||||
|
this.$store.dispatch('queue/clean')
|
||||||
|
this.$store.dispatch('queue/appendMany', {tracks: tracks}).then(() => {
|
||||||
|
this.$store.dispatch('queue/currentIndex', trackIndex)
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!discrete && !iconOnly"
|
v-if="!discrete && !iconOnly"
|
||||||
@click.prevent="clicked = true"
|
@click.stop.prevent="clicked = true"
|
||||||
:class="['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]">
|
:class="['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]">
|
||||||
<i :class="dropdownIconClasses.concat(['icon'])" :title="title" ></i>
|
<i :class="dropdownIconClasses.concat(['icon'])" :title="title" ></i>
|
||||||
<div class="menu" v-if="clicked">
|
<div class="menu" v-if="clicked">
|
||||||
|
@ -27,6 +27,9 @@
|
||||||
<button v-if="track" class="item basic" :disabled="!playable" @click.stop.prevent="$store.dispatch('radios/start', {type: 'similar', objectId: track.id})" :title="labels.startRadio">
|
<button v-if="track" class="item basic" :disabled="!playable" @click.stop.prevent="$store.dispatch('radios/start', {type: 'similar', objectId: track.id})" :title="labels.startRadio">
|
||||||
<i class="feed icon"></i><translate translate-context="*/Queue/Button.Label/Short, Verb">Play radio</translate>
|
<i class="feed icon"></i><translate translate-context="*/Queue/Button.Label/Short, Verb">Play radio</translate>
|
||||||
</button>
|
</button>
|
||||||
|
<button v-if="track" class="item basic" @click.stop.prevent="$router.push(`/library/tracks/${track.id}/`)">
|
||||||
|
<i class="info icon"></i><translate translate-context="*/Queue/Dropdown/Button/Label/Short">Track details</translate>
|
||||||
|
</button>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<button v-if="filterableArtist" ref="filterArtist" data-ref="filterArtist" class="item basic" :disabled="!filterableArtist" @click.stop.prevent="filterArtist" :title="labels.hideArtist">
|
<button v-if="filterableArtist" ref="filterArtist" data-ref="filterArtist" class="item basic" :disabled="!filterableArtist" @click.stop.prevent="filterArtist" :title="labels.hideArtist">
|
||||||
<i class="eye slash outline icon"></i><translate translate-context="*/Queue/Dropdown/Button/Label/Short">Hide content from this artist</translate>
|
<i class="eye slash outline icon"></i><translate translate-context="*/Queue/Dropdown/Button/Label/Short">Hide content from this artist</translate>
|
||||||
|
@ -35,7 +38,7 @@
|
||||||
v-for="obj in getReportableObjs({track, album, artist, playlist, account, channel})"
|
v-for="obj in getReportableObjs({track, album, artist, playlist, account, channel})"
|
||||||
:key="obj.target.type + obj.target.id"
|
:key="obj.target.type + obj.target.id"
|
||||||
class="item basic"
|
class="item basic"
|
||||||
:ref="`report${obj.target.type}${obj.target.id}`" :data-ref="`report${obj.target.type}${obj.target.id}`"
|
:ref="`report${obj.target.type}${obj.target.id}`" :data-ref="`report${obj.target.type}${obj.target.id}`"
|
||||||
@click.stop.prevent="$store.dispatch('moderation/report', obj.target)">
|
@click.stop.prevent="$store.dispatch('moderation/report', obj.target)">
|
||||||
<i class="share icon" /> {{ obj.label }}
|
<i class="share icon" /> {{ obj.label }}
|
||||||
</button>
|
</button>
|
||||||
|
@ -90,7 +93,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
replacePlay = this.$pgettext('*/Queue/Dropdown/Button/Title', 'Play tracks')
|
replacePlay = this.$pgettext('*/Queue/Dropdown/Button/Title', 'Play tracks')
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
playNow: this.$pgettext('*/Queue/Dropdown/Button/Title', 'Play now'),
|
playNow: this.$pgettext('*/Queue/Dropdown/Button/Title', 'Play now'),
|
||||||
addToQueue: this.$pgettext('*/Queue/Dropdown/Button/Title', 'Add to current queue'),
|
addToQueue: this.$pgettext('*/Queue/Dropdown/Button/Title', 'Add to current queue'),
|
||||||
|
@ -143,7 +146,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
filterArtist () {
|
filterArtist () {
|
||||||
this.$store.dispatch('moderation/hide', {type: 'artist', target: this.filterableArtist})
|
this.$store.dispatch('moderation/hide', {type: 'artist', target: this.filterableArtist})
|
||||||
},
|
},
|
||||||
|
@ -175,7 +177,9 @@ export default {
|
||||||
let self = this
|
let self = this
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
let getTracks = new Promise((resolve, reject) => {
|
let getTracks = new Promise((resolve, reject) => {
|
||||||
if (self.track) {
|
if (self.tracks) {
|
||||||
|
resolve(self.tracks)
|
||||||
|
} else if (self.track) {
|
||||||
if (!self.track.uploads || self.track.uploads.length === 0) {
|
if (!self.track.uploads || self.track.uploads.length === 0) {
|
||||||
// fetch uploads from api
|
// fetch uploads from api
|
||||||
axios.get(`tracks/${self.track.id}/`).then((response) => {
|
axios.get(`tracks/${self.track.id}/`).then((response) => {
|
||||||
|
@ -184,8 +188,6 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
resolve([self.track])
|
resolve([self.track])
|
||||||
}
|
}
|
||||||
} else if (self.tracks) {
|
|
||||||
resolve(self.tracks)
|
|
||||||
} else if (self.playlist) {
|
} else if (self.playlist) {
|
||||||
let url = 'playlists/' + self.playlist.id + '/'
|
let url = 'playlists/' + self.playlist.id + '/'
|
||||||
axios.get(url + 'tracks/').then((response) => {
|
axios.get(url + 'tracks/').then((response) => {
|
||||||
|
@ -236,7 +238,14 @@ export default {
|
||||||
let self = this
|
let self = this
|
||||||
self.$store.dispatch('queue/clean')
|
self.$store.dispatch('queue/clean')
|
||||||
this.getPlayableTracks().then((tracks) => {
|
this.getPlayableTracks().then((tracks) => {
|
||||||
self.$store.dispatch('queue/appendMany', {tracks: tracks}).then(() => self.addMessage(tracks))
|
self.$store.dispatch('queue/appendMany', {tracks: tracks}).then(() => {
|
||||||
|
if (self.track) {
|
||||||
|
// set queue position to selected track
|
||||||
|
const trackIndex = self.tracks.findIndex(track => track.id === self.track.id)
|
||||||
|
self.$store.dispatch('queue/currentIndex', trackIndex)
|
||||||
|
}
|
||||||
|
self.addMessage(tracks)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
jQuery(self.$el).find('.ui.dropdown').dropdown('hide')
|
jQuery(self.$el).find('.ui.dropdown').dropdown('hide')
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<play-button :class="['basic', {vibrant: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :is-playable="playable" :track="track"></play-button>
|
<play-button :class="['basic', {vibrant: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']"
|
||||||
|
:discrete="true"
|
||||||
|
:is-playable="playable"
|
||||||
|
:track="track"
|
||||||
|
:track-index="trackIndex"
|
||||||
|
:tracks="tracks"></play-button>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<img alt="" class="ui mini image" v-if="track.album && track.album.cover && track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)">
|
<img alt="" class="ui mini image" v-if="track.album && track.album.cover && track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)">
|
||||||
<img alt="" class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
|
<img alt="" class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
|
||||||
</td>
|
</td>
|
||||||
<td colspan="6">
|
<td colspan="6">
|
||||||
<router-link class="track" :to="{name: 'library.tracks.detail', params: {id: track.id }}">
|
<button class="track" @click.stop="playSong()">
|
||||||
<template v-if="displayPosition && track.position">
|
<template v-if="displayPosition && track.position">
|
||||||
{{ track.position }}.
|
{{ track.position }}.
|
||||||
</template>
|
</template>
|
||||||
{{ track.title|truncate(40) }}
|
{{ track.title|truncate(40) }}
|
||||||
</router-link>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="4">
|
<td colspan="4">
|
||||||
<router-link class="artist discrete link" :to="{name: 'library.artists.detail', params: {id: track.artist.id }}">
|
<router-link class="artist discrete link" :to="{name: 'library.artists.detail', params: {id: track.artist.id }}">
|
||||||
|
@ -56,6 +61,8 @@ import PlayButton from '@/components/audio/PlayButton'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
track: {type: Object, required: true},
|
track: {type: Object, required: true},
|
||||||
|
trackIndex: {type: Number, required: true},
|
||||||
|
tracks: {type: Array, required: false},
|
||||||
artist: {type: Object, required: false},
|
artist: {type: Object, required: false},
|
||||||
displayPosition: {type: Boolean, default: false},
|
displayPosition: {type: Boolean, default: false},
|
||||||
displayActions: {type: Boolean, default: true},
|
displayActions: {type: Boolean, default: true},
|
||||||
|
@ -80,6 +87,16 @@ export default {
|
||||||
return this.track.album.artist
|
return this.track.album.artist
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
playSong () {
|
||||||
|
this.$store.dispatch('queue/clean')
|
||||||
|
this.$store.dispatch('queue/appendMany', {
|
||||||
|
tracks: this.tracks
|
||||||
|
}).then(() => {
|
||||||
|
this.$store.dispatch('queue/currentIndex', this.trackIndex)
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
:display-position="displayPosition"
|
:display-position="displayPosition"
|
||||||
:display-actions="displayActions"
|
:display-actions="displayActions"
|
||||||
:track="track"
|
:track="track"
|
||||||
|
:track-index="index"
|
||||||
|
:tracks="allTracks"
|
||||||
:artist="artist"
|
:artist="artist"
|
||||||
:key="index + '-' + track.id"
|
:key="index + '-' + track.id"
|
||||||
v-for="(track, index) in allTracks"></track-row>
|
v-for="(track, index) in allTracks"></track-row>
|
||||||
|
|
|
@ -11,4 +11,9 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.track {
|
||||||
|
display: block;
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.album-entry:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
// explicitly style the button as if it was hovered itself
|
||||||
|
.ui.inverted.vibrant.button {
|
||||||
|
background-color: var(--vibrant-hover-color);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 0 0 2px var(--vibrant-color) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.album-entry, .channel-entry-card {
|
.album-entry, .channel-entry-card {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
Loading…
Reference in New Issue