Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Philipp Wolfer
funkwhale
Commits
f1f9f935
Verified
Commit
f1f9f935
authored
Feb 24, 2021
by
heyarne
Committed by
Georg Krause
Apr 28, 2021
Browse files
Make playing tracks in their playlist the default
parent
5d745fea
Changes
7
Hide whitespace changes
Inline
Side-by-side
changes/changelog.d/1274.enhancement
0 → 100644
View file @
f1f9f935
Make "play in list" the default when interacting with individual tracks (#1274)
front/src/components/audio/AlbumEntries.vue
View file @
f1f9f935
<
template
>
<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"
>
<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
class=
"position"
>
{{
prettyPosition
(
track
.
position
)
}}
</div>
<div
class=
"content ellipsis"
>
<router-link
:to=
"
{name: 'library.tracks.detail', params: {id: track.id}}" class="discrete link">
<strong>
{{
track
.
title
}}
</strong><br>
</router-link>
<strong>
{{
track
.
title
}}
</strong><br>
</div>
<div
class=
"meta"
>
<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>
</div>
<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>
...
...
@@ -54,7 +52,13 @@ export default {
var
s
=
String
(
position
);
while
(
s
.
length
<
(
size
||
2
))
{
s
=
"
0
"
+
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
>
front/src/components/audio/PlayButton.vue
View file @
f1f9f935
...
...
@@ -11,7 +11,7 @@
</button>
<button
v-if=
"!discrete && !iconOnly"
@
click.prevent=
"clicked = true"
@
click.
stop.
prevent=
"clicked = true"
:class=
"['ui', {disabled: !playable && !filterableArtist}, 'floating', 'dropdown', {'icon': !dropdownOnly}, {'button': !dropdownOnly}]"
>
<i
:class=
"dropdownIconClasses.concat(['icon'])"
:title=
"title"
></i>
<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"
>
<i
class=
"feed icon"
></i><translate
translate-context=
"*/Queue/Button.Label/Short, Verb"
>
Play radio
</translate>
</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>
<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>
...
...
@@ -35,7 +38,7 @@
v-for=
"obj in getReportableObjs({track, album, artist, playlist, account, channel})"
:key=
"obj.target.type + obj.target.id"
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)"
>
<i
class=
"share icon"
/>
{{ obj.label }}
</button>
...
...
@@ -90,7 +93,7 @@ export default {
}
else
{
replacePlay
=
this
.
$pgettext
(
'
*/Queue/Dropdown/Button/Title
'
,
'
Play tracks
'
)
}
return
{
playNow
:
this
.
$pgettext
(
'
*/Queue/Dropdown/Button/Title
'
,
'
Play now
'
),
addToQueue
:
this
.
$pgettext
(
'
*/Queue/Dropdown/Button/Title
'
,
'
Add to current queue
'
),
...
...
@@ -143,7 +146,6 @@ export default {
},
},
methods
:
{
filterArtist
()
{
this
.
$store
.
dispatch
(
'
moderation/hide
'
,
{
type
:
'
artist
'
,
target
:
this
.
filterableArtist
})
},
...
...
@@ -175,7 +177,9 @@ export default {
let
self
=
this
this
.
isLoading
=
true
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
)
{
// fetch uploads from api
axios
.
get
(
`tracks/
${
self
.
track
.
id
}
/`
).
then
((
response
)
=>
{
...
...
@@ -184,8 +188,6 @@ export default {
}
else
{
resolve
([
self
.
track
])
}
}
else
if
(
self
.
tracks
)
{
resolve
(
self
.
tracks
)
}
else
if
(
self
.
playlist
)
{
let
url
=
'
playlists/
'
+
self
.
playlist
.
id
+
'
/
'
axios
.
get
(
url
+
'
tracks/
'
).
then
((
response
)
=>
{
...
...
@@ -236,7 +238,14 @@ export default {
let
self
=
this
self
.
$store
.
dispatch
(
'
queue/clean
'
)
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
'
)
},
...
...
front/src/components/audio/track/Row.vue
View file @
f1f9f935
<
template
>
<tr>
<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>
<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"
>
</td>
<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"
>
{{
track
.
position
}}
.
</
template
>
{{ track.title|truncate(40) }}
</
router-link
>
</
button
>
</td>
<td
colspan=
"4"
>
<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
{
props
:
{
track
:
{
type
:
Object
,
required
:
true
},
trackIndex
:
{
type
:
Number
,
required
:
true
},
tracks
:
{
type
:
Array
,
required
:
false
},
artist
:
{
type
:
Object
,
required
:
false
},
displayPosition
:
{
type
:
Boolean
,
default
:
false
},
displayActions
:
{
type
:
Boolean
,
default
:
true
},
...
...
@@ -80,6 +87,16 @@ export default {
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
>
front/src/components/audio/track/Table.vue
View file @
f1f9f935
...
...
@@ -22,6 +22,8 @@
:display-position=
"displayPosition"
:display-actions=
"displayActions"
:track=
"track"
:track-index=
"index"
:tracks=
"allTracks"
:artist=
"artist"
:key=
"index + '-' + track.id"
v-for=
"(track, index) in allTracks"
></track-row>
...
...
front/src/style/components/_track_table.scss
View file @
f1f9f935
...
...
@@ -11,4 +11,9 @@
visibility
:
hidden
;
}
}
.track
{
display
:
block
;
line-height
:
2
;
}
}
front/src/style/globals/_channels.scss
View file @
f1f9f935
...
...
@@ -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
{
border-radius
:
5px
;
padding
:
0
.5em
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment