[web-src] Add a settings page to the player web interface to change web

interface specific options
This commit is contained in:
chme 2019-07-07 08:22:56 +02:00
parent 2cc310b646
commit 9ab1677f1f
7 changed files with 266 additions and 7 deletions

View File

@ -106,6 +106,7 @@ export default {
vm.update_outputs() vm.update_outputs()
vm.update_player_status() vm.update_player_status()
vm.update_library_stats() vm.update_library_stats()
vm.update_settings()
vm.update_queue() vm.update_queue()
vm.update_spotify() vm.update_spotify()
} }
@ -166,6 +167,12 @@ export default {
}) })
}, },
update_settings: function () {
webapi.settings().then(({ data }) => {
this.$store.commit(types.UPDATE_SETTINGS, data)
})
},
update_spotify: function () { update_spotify: function () {
webapi.spotify().then(({ data }) => { webapi.spotify().then(({ data }) => {
this.$store.commit(types.UPDATE_SPOTIFY, data) this.$store.commit(types.UPDATE_SPOTIFY, data)

View File

@ -121,17 +121,13 @@
<!-- Settings drop down --> <!-- Settings drop down -->
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless"><span class="icon is-hidden-mobile is-hidden-tablet-only"><i class="mdi mdi-settings"></i></span> <span class="is-hidden-desktop has-text-weight-bold">Settings</span></a> <a class="navbar-link is-arrowless"><span class="icon is-hidden-mobile is-hidden-tablet-only"><i class="mdi mdi-settings"></i></span> <span class="is-hidden-desktop has-text-weight-bold">forked-daapd</span></a>
<div class="navbar-dropdown is-right"> <div class="navbar-dropdown is-right">
<a class="navbar-item" href="/admin.html">Admin</a> <a class="navbar-item" href="/admin.html">Admin</a>
<hr class="navbar-divider"> <hr class="navbar-divider">
<navbar-item-link to="/about"> <navbar-item-link to="/settings/webinterface">Settings</navbar-item-link>
<div> <navbar-item-link to="/about">About</navbar-item-link>
<p class="title is-7">forked-daapd</p>
<p class="subtitle is-7">{{ config.version }}</p>
</div>
</navbar-item-link>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,202 @@
<template>
<content-with-heading>
<template slot="heading-left">
<div class="title is-4">Settings</div>
</template>
<template slot="heading-right">
</template>
<template slot="content">
<div class="heading fd-has-margin-bottom">Now playing page</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" :checked="settings_option_show_composer_now_playing" @change="set_timer_show_composer_now_playing" ref="checkbox_show_composer">
Show composer
<i class="is-size-7"
:class="{
'has-text-info': statusUpdateShowComposerNowPlaying === 'success',
'has-text-danger': statusUpdateShowComposerNowPlaying === 'error'
}">{{ info_option_show_composer_now_playing }}</i>
</label>
<p class="help has-text-justified">
If enabled the composer of the current playing track is shown on the &quot;now playing page&quot;
</p>
</div>
<fieldset :disabled="!settings_option_show_composer_now_playing">
<div class="field">
<label class="label has-text-weight-normal">
Show composer only for listed genres
<i class="is-size-7"
:class="{
'has-text-info': statusUpdateShowComposerForGenre === 'success',
'has-text-danger': statusUpdateShowComposerForGenre === 'error'
}">{{ info_option_show_composer_for_genre }}</i>
</label>
<div class="control">
<input class="input" type="text" placeholder="Genres"
:value="settings_option_show_composer_for_genre"
@input="set_timer_show_composer_for_genre"
ref="field_composer_for_genre">
</div>
<p class="help">
Comma separated list of genres the composer should be displayed on the &quot;now playing page&quot;.
</p>
<p class="help">
Leave empty to always show the composer.
</p>
<p class="help">
The genre tag of the current track is matched by checking, if one of the defined genres are included.
For example setting to <code>classical, soundtrack</code> will show the composer for tracks with
a genre tag of &quot;Contemporary Classical&quot;.<br>
</p>
</div>
</fieldset>
</template>
</content-with-heading>
</template>
<script>
import ContentWithHeading from '@/templates/ContentWithHeading'
import webapi from '@/webapi'
import * as types from '@/store/mutation_types'
export default {
name: 'SettingsPageWebinterface',
components: { ContentWithHeading },
data () {
return {
timerDelay: 2000,
timerIdShowComposerNowPlaying: -1,
timerIdShowComposerForGenre: -1,
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
statusUpdateShowComposerNowPlaying: '',
statusUpdateShowComposerForGenre: ''
}
},
computed: {
settings_category_webinterface () {
return this.$store.getters.settings_webinterface
},
settings_option_show_composer_now_playing () {
return this.$store.getters.settings_option_show_composer_now_playing
},
settings_option_show_composer_for_genre () {
return this.$store.getters.settings_option_show_composer_for_genre
},
info_option_show_composer_for_genre () {
if (this.statusUpdateShowComposerForGenre === 'success') {
return '(setting saved)'
} else if (this.statusUpdateShowComposerForGenre === 'error') {
return '(error saving setting)'
}
return ''
},
info_option_show_composer_now_playing () {
if (this.statusUpdateShowComposerNowPlaying === 'success') {
return '(setting saved)'
} else if (this.statusUpdateShowComposerNowPlaying === 'error') {
return '(error saving setting)'
}
return ''
}
},
methods: {
set_timer_show_composer_now_playing () {
if (this.timerIdShowComposerNowPlaying > 0) {
window.clearTimeout(this.timerIdShowComposerNowPlaying)
this.timerIdShowComposerNowPlaying = -1
}
this.statusUpdateShowComposerNowPlaying = ''
const newValue = this.$refs.checkbox_show_composer.checked
if (newValue !== this.settings_option_show_composer_now_playing) {
this.timerIdShowComposerNowPlaying = window.setTimeout(this.update_show_composer_now_playing, this.timerDelay)
}
},
update_show_composer_now_playing () {
this.timerIdShowComposerNowPlaying = -1
const newValue = this.$refs.checkbox_show_composer.checked
if (newValue === this.settings_option_show_composer_now_playing) {
this.statusUpdateShowComposerNowPlaying = ''
return
}
const option = {
category: this.settings_category_webinterface.name,
name: 'show_composer_now_playing',
value: newValue
}
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdateShowComposerNowPlaying = 'success'
}).catch(() => {
this.statusUpdateShowComposerNowPlaying = 'error'
this.$refs.checkbox_show_composer.checked = this.settings_option_show_composer_now_playing
}).finally(() => {
this.timerIdShowComposerNowPlaying = window.setTimeout(this.clear_status_show_composer_now_playing, this.timerDelay)
})
},
set_timer_show_composer_for_genre () {
if (this.timerIdShowComposerForGenre > 0) {
window.clearTimeout(this.timerIdShowComposerForGenre)
this.timerIdShowComposerForGenre = -1
}
this.statusUpdateShowComposerForGenre = ''
const newValue = this.$refs.field_composer_for_genre.value
if (newValue !== this.settings_option_show_composer_for_genre) {
this.timerIdShowComposerForGenre = window.setTimeout(this.update_show_composer_for_genre, this.timerDelay)
}
},
update_show_composer_for_genre () {
this.timerIdShowComposerForGenre = -1
const newValue = this.$refs.field_composer_for_genre.value
if (newValue === this.settings_option_show_composer_for_genre) {
this.statusUpdateShowComposerForGenre = ''
return
}
const option = {
category: this.settings_category_webinterface.name,
name: 'show_composer_for_genre',
value: newValue
}
webapi.settings_update(this.settings_category_webinterface.name, option).then(() => {
this.$store.commit(types.UPDATE_SETTINGS_OPTION, option)
this.statusUpdateShowComposerForGenre = 'success'
}).catch(() => {
this.statusUpdateShowComposerForGenre = 'error'
this.$refs.field_composer_for_genre.value = this.settings_option_show_composer_for_genre
}).finally(() => {
this.timerIdShowComposerForGenre = window.setTimeout(this.clear_status_show_composer_for_genre, this.timerDelay)
})
},
clear_status_show_composer_for_genre () {
this.statusUpdateShowComposerForGenre = ''
},
clear_status_show_composer_now_playing () {
this.statusUpdateShowComposerNowPlaying = ''
}
},
filters: {
}
}
</script>
<style>
</style>

View File

@ -31,6 +31,7 @@ import SpotifyPageArtist from '@/pages/SpotifyPageArtist'
import SpotifyPageAlbum from '@/pages/SpotifyPageAlbum' import SpotifyPageAlbum from '@/pages/SpotifyPageAlbum'
import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist' import SpotifyPagePlaylist from '@/pages/SpotifyPagePlaylist'
import SpotifyPageSearch from '@/pages/SpotifyPageSearch' import SpotifyPageSearch from '@/pages/SpotifyPageSearch'
import SettingsPageWebinterface from '@/pages/SettingsPageWebinterface'
Vue.use(VueRouter) Vue.use(VueRouter)
@ -212,6 +213,11 @@ export const router = new VueRouter({
path: '/search/spotify', path: '/search/spotify',
name: 'Spotify Search', name: 'Spotify Search',
component: SpotifyPageSearch component: SpotifyPageSearch
},
{
path: '/settings/webinterface',
name: 'Settings Webinterface',
component: SettingsPageWebinterface
} }
], ],
scrollBehavior (to, from, savedPosition) { scrollBehavior (to, from, savedPosition) {

View File

@ -11,6 +11,9 @@ export default new Vuex.Store({
'version': '', 'version': '',
'buildoptions': [ ] 'buildoptions': [ ]
}, },
settings: {
'categories': []
},
library: { library: {
'artists': 0, 'artists': 0,
'albums': 0, 'albums': 0,
@ -58,6 +61,33 @@ export default new Vuex.Store({
return item.id === state.player.item_id return item.id === state.player.item_id
}) })
return (item === undefined) ? {} : item return (item === undefined) ? {} : item
},
settings_webinterface: state => {
if (state.settings) {
return state.settings.categories.find(elem => elem.name === 'webinterface')
}
return null
},
settings_option_show_composer_now_playing: (state, getters) => {
if (getters.settings_webinterface) {
const option = getters.settings_webinterface.options.find(elem => elem.name === 'show_composer_now_playing')
if (option) {
return option.value
}
}
return false
},
settings_option_show_composer_for_genre: (state, getters) => {
if (getters.settings_webinterface) {
const option = getters.settings_webinterface.options.find(elem => elem.name === 'show_composer_for_genre')
if (option) {
return option.value
}
}
return null
} }
}, },
@ -65,6 +95,14 @@ export default new Vuex.Store({
[types.UPDATE_CONFIG] (state, config) { [types.UPDATE_CONFIG] (state, config) {
state.config = config state.config = config
}, },
[types.UPDATE_SETTINGS] (state, settings) {
state.settings = settings
},
[types.UPDATE_SETTINGS_OPTION] (state, option) {
const settingCategory = state.settings.categories.find(elem => elem.name === option.category)
const settingOption = settingCategory.options.find(elem => elem.name === option.name)
settingOption.value = option.value
},
[types.UPDATE_LIBRARY_STATS] (state, libraryStats) { [types.UPDATE_LIBRARY_STATS] (state, libraryStats) {
state.library = libraryStats state.library = libraryStats
}, },

View File

@ -1,4 +1,6 @@
export const UPDATE_CONFIG = 'UPDATE_CONFIG' export const UPDATE_CONFIG = 'UPDATE_CONFIG'
export const UPDATE_SETTINGS = 'UPDATE_SETTINGS'
export const UPDATE_SETTINGS_OPTION = 'UPDATE_SETTINGS_OPTION'
export const UPDATE_LIBRARY_STATS = 'UPDATE_LIBRARY_STATS' export const UPDATE_LIBRARY_STATS = 'UPDATE_LIBRARY_STATS'
export const UPDATE_LIBRARY_AUDIOBOOKS_COUNT = 'UPDATE_LIBRARY_AUDIOBOOKS_COUNT' export const UPDATE_LIBRARY_AUDIOBOOKS_COUNT = 'UPDATE_LIBRARY_AUDIOBOOKS_COUNT'
export const UPDATE_LIBRARY_PODCASTS_COUNT = 'UPDATE_LIBRARY_PODCASTS_COUNT' export const UPDATE_LIBRARY_PODCASTS_COUNT = 'UPDATE_LIBRARY_PODCASTS_COUNT'

View File

@ -13,6 +13,14 @@ export default {
return axios.get('/api/config') return axios.get('/api/config')
}, },
settings () {
return axios.get('/api/settings')
},
settings_update (categoryName, option) {
return axios.put('/api/settings/' + categoryName + '/' + option.name, option)
},
library_stats () { library_stats () {
return axios.get('/api/library') return axios.get('/api/library')
}, },