Adds volume control

This commit is contained in:
Ammon Sarver 2021-01-29 17:21:24 -07:00
parent 8022929dc1
commit a0de1f0c5a
4 changed files with 48 additions and 0 deletions

View File

@ -47,6 +47,16 @@
<!-- Controls right ---> <!-- Controls right --->
<div class="col-auto col-sm p-0"> <div class="col-auto col-sm p-0">
<div class="d-flex flex-nowrap justify-content-end pr-3"> <div class="d-flex flex-nowrap justify-content-end pr-3">
<div class="m-0 d-none d-sm-inline-flex align-items-center pr-3">
<Icon class="volume-icon" icon="volume-up-fill" />
<b-form-input
:value="volume"
type="range"
min="0"
max="1"
step="0.05"
@input="setVolume" />
</div>
<b-button variant="link" <b-button variant="link"
class="m-0 d-none d-sm-inline-block" class="m-0 d-none d-sm-inline-block"
:class="{ 'text-primary': shuffleActive }" :class="{ 'text-primary': shuffleActive }"
@ -60,6 +70,18 @@
<Icon icon="arrow-repeat" /> <Icon icon="arrow-repeat" />
</b-button> </b-button>
<OverflowMenu class="d-sm-none"> <OverflowMenu class="d-sm-none">
<b-dropdown-text>
<div class="d-flex justify-content-between">
<strong class="pr-1">Volume</strong>
<b-form-input
:value="volume"
type="range"
min="0"
max="1"
step="0.05"
@input="setVolume" />
</div>
</b-dropdown-text>
<b-dropdown-text> <b-dropdown-text>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<strong>Repeat</strong> <strong>Repeat</strong>
@ -109,6 +131,7 @@
repeatActive: (state: any) => state.repeat, repeatActive: (state: any) => state.repeat,
shuffleActive: (state: any) => state.shuffle, shuffleActive: (state: any) => state.shuffle,
visible: (state: any) => state.queue.length > 0, visible: (state: any) => state.queue.length > 0,
volume: (state: any) => state.volume,
}), }),
...mapGetters('player', [ ...mapGetters('player', [
'track', 'track',
@ -130,6 +153,9 @@
return this.$store.dispatch('player/seek', value) return this.$store.dispatch('player/seek', value)
} }
}, },
setVolume(volume: any) {
return this.$store.dispatch('player/setVolume', parseFloat(volume))
},
} }
}) })
</script> </script>

View File

@ -5,6 +5,7 @@ import { API } from '@/shared/api'
const audio = new Audio() const audio = new Audio()
const storedQueue = JSON.parse(localStorage.getItem('queue') || '[]') const storedQueue = JSON.parse(localStorage.getItem('queue') || '[]')
const storedQueueIndex = parseInt(localStorage.getItem('queueIndex') || '-1') const storedQueueIndex = parseInt(localStorage.getItem('queueIndex') || '-1')
const storedVolume = parseFloat(localStorage.getItem('player.volume') || '0.8')
if (storedQueueIndex > -1 && storedQueueIndex < storedQueue.length) { if (storedQueueIndex > -1 && storedQueueIndex < storedQueue.length) {
audio.src = storedQueue[storedQueueIndex].url audio.src = storedQueue[storedQueueIndex].url
} }
@ -19,6 +20,7 @@ interface State {
currentTime: number; // position of current track in seconds currentTime: number; // position of current track in seconds
repeat: boolean; repeat: boolean;
shuffle: boolean; shuffle: boolean;
volume: number; // integer between 0 and 1 representing the volume of the player
} }
export const playerModule: Module<State, any> = { export const playerModule: Module<State, any> = {
@ -32,6 +34,7 @@ export const playerModule: Module<State, any> = {
currentTime: 0, currentTime: 0,
repeat: localStorage.getItem('player.repeat') !== 'false', repeat: localStorage.getItem('player.repeat') !== 'false',
shuffle: localStorage.getItem('player.shuffle') === 'true', shuffle: localStorage.getItem('player.shuffle') === 'true',
volume: storedVolume,
}, },
mutations: { mutations: {
@ -102,6 +105,10 @@ export const playerModule: Module<State, any> = {
setScrobbled(state) { setScrobbled(state) {
state.scrobbled = true state.scrobbled = true
}, },
setVolume(state, value: any) {
state.volume = value
localStorage.setItem('player.volume', String(value))
}
}, },
actions: { actions: {
@ -176,6 +183,10 @@ export const playerModule: Module<State, any> = {
setNextInQueue({ commit }, track) { setNextInQueue({ commit }, track) {
commit('setNextInQueue', track) commit('setNextInQueue', track)
}, },
setVolume({ commit }, value) {
audio.volume = value
commit('setVolume', value)
},
}, },
getters: { getters: {
@ -207,6 +218,7 @@ export const playerModule: Module<State, any> = {
} }
export function setupAudio(store: Store<any>, api: API) { export function setupAudio(store: Store<any>, api: API) {
audio.volume = store.state.player.volume
audio.ontimeupdate = () => { audio.ontimeupdate = () => {
store.commit('player/setCurrentTime', audio.currentTime) store.commit('player/setCurrentTime', audio.currentTime)

View File

@ -28,6 +28,7 @@
BIconPersonCircle, BIconPersonCircle,
BIconRss, BIconRss,
BIconX, BIconX,
BIconVolumeUpFill,
} from 'bootstrap-vue' } from 'bootstrap-vue'
export default Vue.extend({ export default Vue.extend({
@ -56,6 +57,7 @@
BIconPersonCircle, BIconPersonCircle,
BIconRss, BIconRss,
BIconX, BIconX,
BIconVolumeUpFill,
}, },
props: { props: {
icon: { type: String, required: true } icon: { type: String, required: true }

View File

@ -34,6 +34,9 @@ $dropdown-divider-bg: $theme-elevation-2;
$input-bg: $theme-elevation-2; $input-bg: $theme-elevation-2;
$input-border-color: $theme-elevation-2; $input-border-color: $theme-elevation-2;
$input-color: $theme-text; $input-color: $theme-text;
$custom-range-track-height: 0.1rem;
$custom-range-thumb-bg: $theme-text;
$custom-range-track-bg: $theme-text-muted;
// Other // Other
$progress-bg: rgb(35, 35, 35); $progress-bg: rgb(35, 35, 35);
@ -63,6 +66,11 @@ h1, h2, h3, h4, h5 {
box-shadow: none !important; box-shadow: none !important;
} }
.volume-icon {
font-size: 2.25rem;
padding: 0.375rem;
}
@import './nav'; @import './nav';
@import './table'; @import './table';