Merge branch 'feature/52-shuffle-loop' into 'develop'

Feature/52 shuffle loop

Closes #52

See merge request funkwhale/funkwhale!31
merge-requests/154/head
Eliot Berriot 2017-12-17 16:24:24 +00:00
commit 860b6b1e1f
3 zmienionych plików z 122 dodań i 15 usunięć

Wyświetl plik

@ -8,6 +8,8 @@ Changelog
- Shortcuts: can now use the ``f`` shortcut to toggle the currently playing track
as a favorite (#53)
- Shortcuts: avoid collisions between shortcuts by using the exact modifier (#53)
- Player: Added looping controls and shortcuts (#52)
- Player: Added shuffling controls and shortcuts (#52)
0.2.6 (2017-12-15)

Wyświetl plik

@ -1,10 +1,12 @@
import Vue from 'vue'
import _ from 'lodash'
import logger from '@/logging'
import cache from '@/cache'
import config from '@/config'
import Audio from '@/audio'
import backend from '@/audio/backend'
import radios from '@/radios'
import Vue from 'vue'
import url from '@/utils/url'
import auth from '@/auth'
@ -17,6 +19,7 @@ class Queue {
this.currentTrack = null
this.ended = true
this.state = {
looping: 0, // 0 -> no, 1 -> on track, 2 -> on queue
volume: cache.get('volume', 0.5)
}
this.audio = {
@ -267,12 +270,22 @@ class Queue {
handleAudioEnded (e) {
this.recordListen(this.currentTrack)
if (this.state.looping === 1) {
// we loop on the same track
logger.default.info('Looping on the same track')
return this.play(this.currentIndex)
}
if (this.currentIndex < this.tracks.length - 1) {
logger.default.info('Audio track ended, playing next one')
this.next()
return this.next()
} else {
logger.default.info('We reached the end of the queue')
this.ended = true
if (this.state.looping === 2) {
logger.default.info('Going back to the beginning of the queue')
return this.play(0)
} else {
this.ended = true
}
}
}
@ -297,6 +310,21 @@ class Queue {
}
}
toggleLooping () {
if (this.state.looping > 1) {
this.state.looping = 0
} else {
this.state.looping += 1
}
}
shuffle () {
let tracks = this.tracks
let shuffled = _.shuffle(tracks)
this.clean()
this.appendMany(shuffled)
}
}
let queue = new Queue()

Wyświetl plik

@ -39,21 +39,78 @@
</div>
</div>
<div class="controls ui grid">
<div class="volume-control four wide center aligned column">
<input type="range" step="0.05" min="0" max="1" v-model="sliderVolume" />
<div class="two wide column controls ui grid">
<div
@click="queue.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"
title="Play track"
class="two wide column control">
<i :class="['ui', 'play', {'disabled': !queue.currentTrack}, 'big', 'icon']"></i>
</div>
<div
v-else
@click="pauseOrPlay"
title="Pause track"
class="two wide column control">
<i :class="['ui', 'pause', {'disabled': !queue.currentTrack}, 'big', 'icon']"></i>
</div>
<div
@click="queue.next()"
title="Next track"
class="two wide column control"
:disabled="!hasNext">
<i :class="['ui', {'disabled': !hasPrevious}, '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>
<input type="range" step="0.05" min="0" max="1" v-model="sliderVolume" />
</div>
<div class="eight wide center aligned column">
<i title="Previous track" @click="queue.previous()" :class="['ui', {'disabled': !hasPrevious}, 'step', 'backward', 'big', 'icon']" :disabled="!hasPrevious"></i>
<i title="Play track" v-if="!queue.audio.state.playing" :class="['ui', 'play', {'disabled': !queue.currentTrack}, 'big', 'icon']" @click="pauseOrPlay"></i>
<i title="Pause track" v-else :class="['ui', 'pause', {'disabled': !queue.currentTrack}, 'big', 'icon']" @click="pauseOrPlay"></i>
<i title="Next track" @click="queue.next()" :class="['ui', 'step', 'forward', {'disabled': !hasNext}, 'big', 'icon']" :disabled="!hasNext"></i>
<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>
<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"
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"
class="repeat orange secondary icon">
</i>
</div>
<div class="four wide center aligned column">
<i title="Clear your queue" @click="queue.clean()" :class="['ui', 'trash', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" :disabled="queue.tracks.length === 0"></i>
<div
@click="queue.shuffle()"
:disabled="queue.tracks.length === 0"
title="Shuffle your queue"
class="two wide column control">
<i :class="['ui', 'random', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i>
</div>
<div class="one wide column"></div>
<div
@click="queue.clean()"
:disabled="queue.tracks.length === 0"
title="Clear your queue"
class="two wide column control">
<i :class="['ui', 'trash', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i>
</div>
</div>
<GlobalEvents
@ -63,6 +120,8 @@
@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"
/>
</div>
@ -187,14 +246,32 @@ export default {
.volume-control {
position: relative;
.icon {
margin: 0;
// margin: 0;
}
[type="range"] {
max-width: 75%;
max-width: 100%;
position: absolute;
bottom: 5px;
left: 10%;
cursor: pointer;
display: none;
}
&:hover {
[type="range"] {
display: block;
}
}
}
.looping.control {
i {
position: relative;
}
.label {
position: absolute;
font-size: 0.7rem;
bottom: -0.7rem;
right: -0.7rem;
}
}
.ui.feed.icon {