2021-04-25 11:03:46 +02:00

156 lines
5.4 KiB
Vue

<template>
<div :class="{'visible': visible}" class="player elevated d-flex">
<div class="flex-fill">
<!-- Progress --->
<div class="progress2" @click="seek">
<b-progress :value="progress" :max="100" height="4px" />
</div>
<div class="row align-items-center m-0">
<!-- Track info --->
<div class="col p-0 d-flex flex-nowrap align-items-center justify-content-start" style="width: 0; min-width: 0">
<template v-if="track">
<router-link :to="{ name: 'queue' }" style="padding: 12px">
<img v-if="track.image" width="52px" height="52px" :src="track.image">
<img v-else width="52px" height="52px" src="@/shared/assets/fallback.svg">
</router-link>
<div style="min-width: 0">
<div class="text-truncate">
{{ track.title }}
</div>
<div class="text-truncate text-muted">
{{ track.artist || track.album || track.description }}
</div>
</div>
</template>
</div>
<!-- Controls--->
<div class="col-auto p-0">
<b-button variant="link" class="m-2 d-none d-sm-inline-block" @click="previous">
<Icon icon="skip-start-fill" />
</b-button>
<b-button variant="link" size="lg" class="m-2" @click="playPause">
<Icon :icon="isPlaying ? 'pause-fill' : 'play-fill'" />
</b-button>
<b-button variant="link" class="m-2" @click="next">
<Icon icon="skip-end-fill" />
</b-button>
</div>
<!-- Controls right --->
<div class="col-auto col-sm p-0">
<div class="d-flex flex-nowrap justify-content-end pr-3">
<div class="m-0 d-none d-md-inline-flex align-items-center">
<b-button variant="link" @click="toggleMute">
<Icon :icon="muteActive ? 'volume-mute-fill' : 'volume-up-fill'" />
</b-button>
<b-form-input type="range" min="0" max="1" step="0.05"
style="width: 120px; min-width: 0; padding-right: 0.75rem"
:title="`Volume: ${Math.round(volume * 100)}%`"
:value="muteActive ? 0.0 : volume" @input="setVolume" />
<b-button title="Shuffle"
variant="link" class="m-0" :class="{ 'text-primary': shuffleActive }"
@click="toggleShuffle">
<Icon icon="shuffle" />
</b-button>
<b-button title="Repeat"
variant="link" class="m-0" :class="{ 'text-primary': repeatActive }"
@click="toggleRepeat">
<Icon icon="arrow-repeat" />
</b-button>
</div>
<OverflowMenu class="d-md-none">
<b-dropdown-text>
<div class="d-flex justify-content-between">
<strong>Volume</strong>
<b-form-input
class="px-2" style="width: 120px"
type="range" min="0" max="1" step="0.05"
:value="volume" @input="setVolume"
/>
</div>
</b-dropdown-text>
<b-dropdown-text>
<div class="d-flex justify-content-between">
<strong>Repeat</strong>
<b-form-checkbox switch :checked="repeatActive" @change="toggleRepeat" />
</div>
</b-dropdown-text>
<b-dropdown-text>
<div class="d-flex justify-content-between">
<strong>Shuffle</strong>
<b-form-checkbox switch :checked="shuffleActive" @change="toggleShuffle" />
</div>
</b-dropdown-text>
</OverflowMenu>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.progress2 {
cursor: pointer;
}
.player {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 0;
max-height: 0;
transition: max-height 0.5s;
}
.visible {
height: auto;
max-height: 100px;
}
.b-icon {
display: flex;
align-items: center;
}
</style>
<script lang="ts">
import Vue from 'vue'
import { mapState, mapGetters, mapActions } from 'vuex'
export default Vue.extend({
computed: {
...mapState('player', {
isPlaying: (state: any) => state.isPlaying,
currentTime: (state: any) => state.currentTime,
repeatActive: (state: any) => state.repeat,
shuffleActive: (state: any) => state.shuffle,
muteActive: (state: any) => state.mute,
visible: (state: any) => state.queue.length > 0,
volume: (state: any) => state.volume,
}),
...mapGetters('player', [
'track',
'progress',
]),
},
methods: {
...mapActions('player', [
'playPause',
'next',
'previous',
'toggleRepeat',
'toggleShuffle',
'toggleMute',
]),
seek(event: any) {
if (event.target) {
const width = event.currentTarget.clientWidth
const value = event.offsetX / width
return this.$store.dispatch('player/seek', value)
}
},
setVolume(volume: any) {
return this.$store.dispatch('player/setVolume', parseFloat(volume))
},
}
})
</script>