add shuffle and repeat toggle
This commit is contained in:
parent
554d58f04b
commit
c751194c16
@ -44,10 +44,21 @@
|
||||
</b-button>
|
||||
</div>
|
||||
|
||||
<!-- Time --->
|
||||
<div class="col p-0 d-none d-sm-block" style="min-width: 0; width: 0;">
|
||||
<div v-if="track" class="pr-3 text-right text-truncate">
|
||||
{{ $formatDuration(currentTime) }} / {{ $formatDuration(duration) }}
|
||||
<!-- Controls right --->
|
||||
<div class="col p-0 d-none d-sm-block " style="min-width: 0; width: 0;">
|
||||
<div class="d-flex justify-content-end pr-3">
|
||||
<b-button variant="link"
|
||||
class="m-0 d-none d-sm-inline-block"
|
||||
:class="{ 'text-primary': shuffleActive }"
|
||||
@click="toggleShuffle">
|
||||
<Icon icon="shuffle" />
|
||||
</b-button>
|
||||
<b-button variant="link"
|
||||
class="m-0 d-none d-sm-inline-block "
|
||||
:class="{ 'text-primary': repeatActive }"
|
||||
@click="toggleRepeat">
|
||||
<Icon icon="arrow-repeat" />
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,7 +92,8 @@
|
||||
...mapState('player', {
|
||||
isPlaying: (state: any) => state.isPlaying,
|
||||
currentTime: (state: any) => state.currentTime,
|
||||
duration: (state: any) => state.duration,
|
||||
repeatActive: (state: any) => state.repeat,
|
||||
shuffleActive: (state: any) => state.shuffle,
|
||||
visible: (state: any) => state.queue.length > 0,
|
||||
}),
|
||||
...mapGetters('player', [
|
||||
@ -94,6 +106,8 @@
|
||||
'playPause',
|
||||
'next',
|
||||
'previous',
|
||||
'toggleRepeat',
|
||||
'toggleShuffle',
|
||||
]),
|
||||
seek(event: any) {
|
||||
if (event.target) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Store, Module } from 'vuex'
|
||||
import { trackListEquals } from '@/shared/utils'
|
||||
import { shuffle, trackListEquals } from '@/shared/utils'
|
||||
|
||||
const audio = new Audio()
|
||||
const storedQueue = JSON.parse(localStorage.getItem('queue') || '[]')
|
||||
@ -15,6 +15,8 @@ interface State {
|
||||
isPlaying: boolean;
|
||||
duration: number; // duration of current track in seconds
|
||||
currentTime: number; // position of current track in seconds
|
||||
repeat: boolean;
|
||||
shuffle: boolean;
|
||||
}
|
||||
|
||||
export const playerModule: Module<State, any> = {
|
||||
@ -25,6 +27,8 @@ export const playerModule: Module<State, any> = {
|
||||
isPlaying: false,
|
||||
duration: 0,
|
||||
currentTime: 0,
|
||||
repeat: localStorage.getItem('player.repeat') !== 'false',
|
||||
shuffle: localStorage.getItem('player.shuffle') === 'true',
|
||||
},
|
||||
|
||||
mutations: {
|
||||
@ -43,6 +47,14 @@ export const playerModule: Module<State, any> = {
|
||||
setPosition(state, time: number) {
|
||||
audio.currentTime = time
|
||||
},
|
||||
setRepeat(state, enable) {
|
||||
state.repeat = enable
|
||||
localStorage.setItem('player.repeat', enable)
|
||||
},
|
||||
setShuffle(state, enable) {
|
||||
state.shuffle = enable
|
||||
localStorage.setItem('player.shuffle', enable)
|
||||
},
|
||||
setQueue(state, queue) {
|
||||
state.queue = queue
|
||||
state.queueIndex = -1
|
||||
@ -89,10 +101,23 @@ export const playerModule: Module<State, any> = {
|
||||
|
||||
actions: {
|
||||
async playTrackList({ commit, state }, { tracks, index }) {
|
||||
if (!trackListEquals(state.queue, tracks)) {
|
||||
commit('setQueue', [...tracks])
|
||||
if (trackListEquals(state.queue, tracks)) {
|
||||
commit('setQueueIndex', index)
|
||||
commit('setPlaying')
|
||||
await audio.play()
|
||||
return
|
||||
}
|
||||
tracks = [...tracks]
|
||||
if (state.shuffle) {
|
||||
const selected = tracks[index]
|
||||
tracks.splice(index, 1)
|
||||
tracks = [selected, ...shuffle(tracks)]
|
||||
commit('setQueue', tracks)
|
||||
commit('setQueueIndex', 0)
|
||||
} else {
|
||||
commit('setQueue', tracks)
|
||||
commit('setQueueIndex', index)
|
||||
}
|
||||
commit('setQueueIndex', index)
|
||||
commit('setPlaying')
|
||||
await audio.play()
|
||||
},
|
||||
@ -125,6 +150,16 @@ export const playerModule: Module<State, any> = {
|
||||
commit('setPosition', state.duration * value)
|
||||
}
|
||||
},
|
||||
resetQueue({ commit }) {
|
||||
audio.pause()
|
||||
commit('setQueueIndex', 0)
|
||||
commit('setPaused')
|
||||
},
|
||||
toggleRepeat({ commit, state }) {
|
||||
commit('setRepeat', !state.repeat)
|
||||
},
|
||||
toggleShuffle({ commit, state }) {
|
||||
commit('setShuffle', !state.shuffle)
|
||||
},
|
||||
addToQueue({ commit }, track) {
|
||||
commit('addToQueue', track)
|
||||
@ -167,7 +202,11 @@ export function setupAudio(store: Store<any>) {
|
||||
store.commit('player/setDuration', audio.duration)
|
||||
}
|
||||
audio.onended = () => {
|
||||
store.dispatch('player/next')
|
||||
if (store.state.repeat) {
|
||||
store.dispatch('player/next')
|
||||
} else {
|
||||
store.dispatch('player/resetQueue')
|
||||
}
|
||||
}
|
||||
audio.onerror = () => {
|
||||
store.commit('player/setPaused')
|
||||
|
@ -5,6 +5,7 @@
|
||||
import Vue from 'vue'
|
||||
import {
|
||||
BIcon,
|
||||
BIconArrowRepeat,
|
||||
BIconBoxArrowUpRight,
|
||||
BIconBroadcast,
|
||||
BIconCardText,
|
||||
@ -17,6 +18,7 @@
|
||||
BIconList,
|
||||
BIconPlayFill,
|
||||
BIconPauseFill,
|
||||
BIconShuffle,
|
||||
BIconSkipStartFill,
|
||||
BIconSkipEndFill,
|
||||
BIconPlus,
|
||||
@ -30,6 +32,7 @@
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
BIcon,
|
||||
BIconArrowRepeat,
|
||||
BIconBoxArrowUpRight,
|
||||
BIconBroadcast,
|
||||
BIconCardText,
|
||||
@ -42,6 +45,7 @@
|
||||
BIconList,
|
||||
BIconPlayFill,
|
||||
BIconPauseFill,
|
||||
BIconShuffle,
|
||||
BIconSkipStartFill,
|
||||
BIconSkipEndFill,
|
||||
BIconPlus,
|
||||
|
@ -9,6 +9,14 @@ export function randomString(): string {
|
||||
return String.fromCharCode.apply(null, Array.from(arr))
|
||||
}
|
||||
|
||||
export function shuffle(a: any[]) {
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
export function md5(str: string): string {
|
||||
return MD5.hash(str)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user