mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-04 20:49:16 +02:00
Now use vuex to manage state for player/queue/radios
This commit is contained in:
parent
254996453f
commit
df94ae37bf
16 changed files with 563 additions and 694 deletions
|
@ -1,104 +1,112 @@
|
|||
<template>
|
||||
<div class="player">
|
||||
<div v-if="queue.currentTrack" class="track-area ui items">
|
||||
<audio-track
|
||||
ref="currentAudio"
|
||||
v-if="currentTrack"
|
||||
:key="(currentIndex, currentTrack.id)"
|
||||
:is-current="true"
|
||||
:track="currentTrack">
|
||||
</audio-track>
|
||||
|
||||
<div v-if="currentTrack" class="track-area ui items">
|
||||
<div class="ui inverted item">
|
||||
<div class="ui tiny image">
|
||||
<img v-if="queue.currentTrack.album.cover" :src="Track.getCover(queue.currentTrack)">
|
||||
<img v-if="currentTrack.album.cover" :src="Track.getCover(currentTrack)">
|
||||
<img v-else src="../../assets/audio/default-cover.png">
|
||||
</div>
|
||||
<div class="middle aligned content">
|
||||
<router-link class="small header discrete link track" :to="{name: 'library.tracks.detail', params: {id: queue.currentTrack.id }}">
|
||||
{{ queue.currentTrack.title }}
|
||||
<router-link class="small header discrete link track" :to="{name: 'library.tracks.detail', params: {id: currentTrack.id }}">
|
||||
{{ currentTrack.title }}
|
||||
</router-link>
|
||||
<div class="meta">
|
||||
<router-link class="artist" :to="{name: 'library.artists.detail', params: {id: queue.currentTrack.artist.id }}">
|
||||
{{ queue.currentTrack.artist.name }}
|
||||
<router-link class="artist" :to="{name: 'library.artists.detail', params: {id: currentTrack.artist.id }}">
|
||||
{{ currentTrack.artist.name }}
|
||||
</router-link> /
|
||||
<router-link class="album" :to="{name: 'library.albums.detail', params: {id: queue.currentTrack.album.id }}">
|
||||
{{ queue.currentTrack.album.title }}
|
||||
<router-link class="album" :to="{name: 'library.albums.detail', params: {id: currentTrack.album.id }}">
|
||||
{{ currentTrack.album.title }}
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="description">
|
||||
<track-favorite-icon :track="queue.currentTrack"></track-favorite-icon>
|
||||
<track-favorite-icon :track="currentTrack"></track-favorite-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-area" v-if="queue.currentTrack">
|
||||
<div class="progress-area" v-if="currentTrack">
|
||||
<div class="ui grid">
|
||||
<div class="left floated four wide column">
|
||||
<p class="timer start" @click="queue.audio.setTime(0)">{{queue.audio.state.currentTimeFormat}}</p>
|
||||
<p class="timer start" @click="updateProgress(0)">{{currentTimeFormatted}}</p>
|
||||
</div>
|
||||
|
||||
<div class="right floated four wide column">
|
||||
<p class="timer total">{{queue.audio.state.durationTimerFormat}}</p>
|
||||
<p class="timer total">{{durationFormatted}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="progress" class="ui small orange inverted progress" @click="touchProgress">
|
||||
<div class="bar" :data-percent="queue.audio.state.progress" :style="{ 'width': queue.audio.state.progress + '%' }"></div>
|
||||
<div class="bar" :data-percent="progress" :style="{ 'width': progress + '%' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="two wide column controls ui grid">
|
||||
<div
|
||||
@click="queue.previous()"
|
||||
@click="previous"
|
||||
title="Previous track"
|
||||
class="two wide column control"
|
||||
:disabled="!hasPrevious">
|
||||
<i :class="['ui', {'disabled': !hasPrevious}, 'step', 'backward', 'big', 'icon']" ></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="!queue.audio.state.playing"
|
||||
@click="pauseOrPlay"
|
||||
v-if="!playing"
|
||||
@click="togglePlay"
|
||||
title="Play track"
|
||||
class="two wide column control">
|
||||
<i :class="['ui', 'play', {'disabled': !queue.currentTrack}, 'big', 'icon']"></i>
|
||||
<i :class="['ui', 'play', {'disabled': !currentTrack}, 'big', 'icon']"></i>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
@click="pauseOrPlay"
|
||||
@click="togglePlay"
|
||||
title="Pause track"
|
||||
class="two wide column control">
|
||||
<i :class="['ui', 'pause', {'disabled': !queue.currentTrack}, 'big', 'icon']"></i>
|
||||
<i :class="['ui', 'pause', {'disabled': !currentTrack}, 'big', 'icon']"></i>
|
||||
</div>
|
||||
<div
|
||||
@click="queue.next()"
|
||||
@click="next"
|
||||
title="Next track"
|
||||
class="two wide column control"
|
||||
:disabled="!hasNext">
|
||||
<i :class="['ui', {'disabled': !hasPrevious}, 'step', 'forward', 'big', 'icon']" ></i>
|
||||
<i :class="['ui', {'disabled': !hasNext}, 'step', 'forward', 'big', 'icon']" ></i>
|
||||
</div>
|
||||
<div class="two wide column control volume-control">
|
||||
<i title="Unmute" @click="queue.setVolume(1)" v-if="currentVolume === 0" class="volume off secondary icon"></i>
|
||||
<i title="Mute" @click="queue.setVolume(0)" v-else-if="currentVolume < 0.5" class="volume down secondary icon"></i>
|
||||
<i title="Mute" @click="queue.setVolume(0)" v-else class="volume up secondary icon"></i>
|
||||
<i title="Unmute" @click="$store.commit('player/volume', 1)" v-if="volume === 0" class="volume off secondary icon"></i>
|
||||
<i title="Mute" @click="$store.commit('player/volume', 0)" v-else-if="volume < 0.5" class="volume down secondary icon"></i>
|
||||
<i title="Mute" @click="$store.commit('player/volume', 0)" v-else class="volume up secondary icon"></i>
|
||||
<input type="range" step="0.05" min="0" max="1" v-model="sliderVolume" />
|
||||
</div>
|
||||
<div class="two wide column control looping">
|
||||
<i
|
||||
title="Looping disabled. Click to switch to single-track looping."
|
||||
v-if="queue.state.looping === 0"
|
||||
@click="queue.state.looping = 1"
|
||||
:disabled="!queue.currentTrack"
|
||||
:class="['ui', {'disabled': !queue.currentTrack}, 'step', 'repeat', 'secondary', 'icon']"></i>
|
||||
v-if="looping === 0"
|
||||
@click="$store.commit('player/looping', 1)"
|
||||
:disabled="!currentTrack"
|
||||
:class="['ui', {'disabled': !currentTrack}, 'step', 'repeat', 'secondary', 'icon']"></i>
|
||||
<i
|
||||
title="Looping on a single track. Click to switch to whole queue looping."
|
||||
v-if="queue.state.looping === 1"
|
||||
@click="queue.state.looping = 2"
|
||||
:disabled="!queue.currentTrack"
|
||||
v-if="looping === 1"
|
||||
@click="$store.commit('player/looping', 2)"
|
||||
:disabled="!currentTrack"
|
||||
class="repeat secondary icon">
|
||||
<span class="ui circular tiny orange label">1</span>
|
||||
</i>
|
||||
<i
|
||||
title="Looping on whole queue. Click to disable looping."
|
||||
v-if="queue.state.looping === 2"
|
||||
@click="queue.state.looping = 0"
|
||||
:disabled="!queue.currentTrack"
|
||||
v-if="looping === 2"
|
||||
@click="$store.commit('player/looping', 0)"
|
||||
:disabled="!currentTrack"
|
||||
class="repeat orange secondary icon">
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
@click="queue.shuffle()"
|
||||
@click="shuffle()"
|
||||
:disabled="queue.tracks.length === 0"
|
||||
title="Shuffle your queue"
|
||||
class="two wide column control">
|
||||
|
@ -106,7 +114,7 @@
|
|||
</div>
|
||||
<div class="one wide column"></div>
|
||||
<div
|
||||
@click="queue.clean()"
|
||||
@click="clean()"
|
||||
:disabled="queue.tracks.length === 0"
|
||||
title="Clear your queue"
|
||||
class="two wide column control">
|
||||
|
@ -114,79 +122,87 @@
|
|||
</div>
|
||||
</div>
|
||||
<GlobalEvents
|
||||
@keydown.space.prevent.exact="pauseOrPlay"
|
||||
@keydown.ctrl.left.prevent.exact="queue.previous"
|
||||
@keydown.ctrl.right.prevent.exact="queue.next"
|
||||
@keydown.ctrl.down.prevent.exact="queue.incrementVolume(-0.1)"
|
||||
@keydown.ctrl.up.prevent.exact="queue.incrementVolume(0.1)"
|
||||
@keydown.f.prevent.exact="favoriteTracks.toggle(queue.currentTrack.id)"
|
||||
@keydown.l.prevent.exact="queue.toggleLooping"
|
||||
@keydown.s.prevent.exact="queue.shuffle"
|
||||
@keydown.space.prevent.exact="togglePlay"
|
||||
@keydown.ctrl.left.prevent.exact="previous"
|
||||
@keydown.ctrl.right.prevent.exact="next"
|
||||
@keydown.ctrl.down.prevent.exact="$store.commit('player/incrementVolume', -0.1)"
|
||||
@keydown.ctrl.up.prevent.exact="$store.commit('player/incrementVolume', 0.1)"
|
||||
@keydown.f.prevent.exact="favoriteTracks.toggle(currentTrack.id)"
|
||||
@keydown.l.prevent.exact="$store.commit('player/toggleLooping')"
|
||||
@keydown.s.prevent.exact="shuffle"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState, mapGetters, mapActions} from 'vuex'
|
||||
import GlobalEvents from '@/components/utils/global-events'
|
||||
|
||||
import favoriteTracks from '@/favorites/tracks'
|
||||
import queue from '@/audio/queue'
|
||||
import radios from '@/radios'
|
||||
import Track from '@/audio/track'
|
||||
import AudioTrack from '@/components/audio/Track'
|
||||
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
|
||||
|
||||
export default {
|
||||
name: 'player',
|
||||
components: {
|
||||
TrackFavoriteIcon,
|
||||
GlobalEvents
|
||||
GlobalEvents,
|
||||
AudioTrack
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
sliderVolume: this.currentVolume,
|
||||
queue: queue,
|
||||
sliderVolume: this.volume,
|
||||
Track: Track,
|
||||
favoriteTracks,
|
||||
radios
|
||||
favoriteTracks
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// we trigger the watcher explicitely it does not work otherwise
|
||||
this.sliderVolume = this.currentVolume
|
||||
this.sliderVolume = this.volume
|
||||
},
|
||||
methods: {
|
||||
pauseOrPlay () {
|
||||
if (this.queue.audio.state.playing) {
|
||||
this.queue.audio.pause()
|
||||
} else {
|
||||
this.queue.audio.play()
|
||||
}
|
||||
},
|
||||
...mapActions({
|
||||
pause: 'player/pause',
|
||||
togglePlay: 'player/togglePlay',
|
||||
clean: 'queue/clean',
|
||||
next: 'queue/next',
|
||||
previous: 'queue/previous',
|
||||
shuffle: 'queue/shuffle',
|
||||
updateProgress: 'player/updateProgress'
|
||||
}),
|
||||
touchProgress (e) {
|
||||
let time
|
||||
let target = this.$refs.progress
|
||||
time = e.layerX / target.offsetWidth * this.queue.audio.state.duration
|
||||
this.queue.audio.setTime(time)
|
||||
time = e.layerX / target.offsetWidth * this.duration
|
||||
this.$refs.currentAudio.setCurrentTime(time)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasPrevious () {
|
||||
return this.queue.currentIndex > 0
|
||||
},
|
||||
hasNext () {
|
||||
return this.queue.currentIndex < this.queue.tracks.length - 1
|
||||
},
|
||||
currentVolume () {
|
||||
return this.queue.audio.state.volume
|
||||
}
|
||||
...mapState({
|
||||
currentIndex: state => state.queue.currentIndex,
|
||||
playing: state => state.player.playing,
|
||||
volume: state => state.player.volume,
|
||||
looping: state => state.player.looping,
|
||||
duration: state => state.player.duration,
|
||||
queue: state => state.queue
|
||||
}),
|
||||
...mapGetters({
|
||||
currentTrack: 'queue/currentTrack',
|
||||
hasNext: 'queue/hasNext',
|
||||
hasPrevious: 'queue/hasPrevious',
|
||||
durationFormatted: 'player/durationFormatted',
|
||||
currentTimeFormatted: 'player/currentTimeFormatted',
|
||||
progress: 'player/progress'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
currentVolume (newValue) {
|
||||
volume (newValue) {
|
||||
this.sliderVolume = newValue
|
||||
},
|
||||
sliderVolume (newValue) {
|
||||
this.queue.setVolume(parseFloat(newValue))
|
||||
this.$store.commit('player/volume', newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue