mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-25 22:55:56 -05:00
[web] Improve user interaction with sliders for output volume and music progress bar #1620
The sliders for output volume and the music slider have been optimised and simplified (one library less) to ensure easier user interaction.
This commit is contained in:
parent
b7a52d1761
commit
eeb4d328c8
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
65
web-src/package-lock.json
generated
65
web-src/package-lock.json
generated
@ -11,7 +11,6 @@
|
||||
"@aacassandra/vue3-progressbar": "^1.0.3",
|
||||
"@mdi/js": "^6.7.96",
|
||||
"@ts-pro/vue-eternal-loading": "^1.2.0",
|
||||
"@vueform/slider": "github:chme/slider#faff83ed8a77f2cdbcb7252505ef734301efd139",
|
||||
"axios": "^1.4.0",
|
||||
"bulma": "^0.9.4",
|
||||
"bulma-switch": "^2.0.4",
|
||||
@ -36,7 +35,7 @@
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-vue": "^9.14.1",
|
||||
"prettier": "^2.8.8",
|
||||
"sass": "^1.62.1",
|
||||
"sass": "^1.63.5",
|
||||
"vite": "^2.9.16"
|
||||
}
|
||||
},
|
||||
@ -50,9 +49,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.22.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz",
|
||||
"integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
|
||||
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@ -124,9 +123,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
|
||||
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
|
||||
"version": "8.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz",
|
||||
"integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -481,16 +480,10 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||
},
|
||||
"node_modules/@vueform/slider": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "git+ssh://git@github.com/chme/slider.git#faff83ed8a77f2cdbcb7252505ef734301efd139",
|
||||
"integrity": "sha512-IfGEwBS5hwptmLbcnjrhDB7olw8mhCbQFDYv24bfYK/LVJo8pueumd7qsO9qlwfyezgnBdp1/CGBm+Wrh1oYdA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.8.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
||||
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
|
||||
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
@ -745,9 +738,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.2.tgz",
|
||||
"integrity": "sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==",
|
||||
"version": "3.31.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz",
|
||||
"integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@ -1197,15 +1190,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.42.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
|
||||
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
|
||||
"version": "8.43.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz",
|
||||
"integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.4.0",
|
||||
"@eslint/eslintrc": "^2.0.3",
|
||||
"@eslint/js": "8.42.0",
|
||||
"@eslint/js": "8.43.0",
|
||||
"@humanwhocodes/config-array": "^0.11.10",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
@ -1265,9 +1258,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.14.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.14.1.tgz",
|
||||
"integrity": "sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw==",
|
||||
"version": "9.15.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.15.0.tgz",
|
||||
"integrity": "sha512-XYzpK6e2REli100+6iCeBA69v6Sm0D/yK2FZP+fCeNt0yH/m82qZQq+ztseyV0JsKdhFysuSEzeE1yCmSC92BA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.3.0",
|
||||
@ -2399,9 +2392,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.62.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
|
||||
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
|
||||
"version": "1.63.5",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.63.5.tgz",
|
||||
"integrity": "sha512-Q6c5gs482oezdAp+0fWF9cRisvpy7yfYb64knID0OE8AnMgtkluRPfpGMFjeD4/+M4+6QpJZCU6JRSxbjiktkg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
@ -2416,9 +2409,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
|
||||
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz",
|
||||
"integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
@ -2645,9 +2638,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.0.tgz",
|
||||
"integrity": "sha512-48IxT9d0+wArT1+3wNIy0tascRoywqSUe2E1YalIC1L8jsUGe5aJQItWfRok7DVFGz3UYvzEI7n5wiTXsCMAcQ==",
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz",
|
||||
"integrity": "sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"build": "vite build --base='./'",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
|
||||
"dev": "vite",
|
||||
"format": "prettier . --write",
|
||||
"format": "prettier . --write",
|
||||
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\"",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
@ -14,7 +14,6 @@
|
||||
"@aacassandra/vue3-progressbar": "^1.0.3",
|
||||
"@mdi/js": "^6.7.96",
|
||||
"@ts-pro/vue-eternal-loading": "^1.2.0",
|
||||
"@vueform/slider": "github:chme/slider#faff83ed8a77f2cdbcb7252505ef734301efd139",
|
||||
"axios": "^1.4.0",
|
||||
"bulma": "^0.9.4",
|
||||
"bulma-switch": "^2.0.4",
|
||||
@ -39,7 +38,7 @@
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-vue": "^9.14.1",
|
||||
"prettier": "^2.8.8",
|
||||
"sass": "^1.62.1",
|
||||
"sass": "^1.63.5",
|
||||
"vite": "^2.9.16"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<navbar-top />
|
||||
<vue-progress-bar class="fd-progress-bar" />
|
||||
<router-view v-slot="{ Component }">
|
||||
<component :is="Component" class="fd-page" />
|
||||
<component :is="Component" />
|
||||
</router-view>
|
||||
|
||||
<modal-dialog-remote-pairing
|
||||
|
@ -115,14 +115,13 @@
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider
|
||||
<input
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
class="slider"
|
||||
max="100"
|
||||
type="range"
|
||||
:style="{ '--ratio': player.volume / 100 }"
|
||||
@change="change_volume"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -175,15 +174,15 @@
|
||||
/></span>
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
<input
|
||||
v-model="stream_volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!playing"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
class="slider"
|
||||
:class="{ 'is-inactive': !playing }"
|
||||
max="100"
|
||||
type="range"
|
||||
:style="{ '--ratio': stream_volume / 100 }"
|
||||
@change="change_stream_volume"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -238,14 +237,13 @@
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider
|
||||
<input
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
class="slider"
|
||||
max="100"
|
||||
type="range"
|
||||
:style="{ '--ratio': player.volume / 100 }"
|
||||
@change="change_volume"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -260,7 +258,7 @@
|
||||
/>
|
||||
<!-- Outputs: stream volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item fd-has-margin-bottom">
|
||||
<div class="navbar-item mb-5">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
@ -298,15 +296,15 @@
|
||||
/></span>
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
<input
|
||||
v-model="stream_volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!playing"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
class="slider"
|
||||
:class="{ 'is-inactive': !playing }"
|
||||
max="100"
|
||||
type="range"
|
||||
:style="{ '--ratio': stream_volume / 100 }"
|
||||
@change="change_stream_volume"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -331,7 +329,6 @@ import PlayerButtonConsume from '@/components/PlayerButtonConsume.vue'
|
||||
import PlayerButtonRepeat from '@/components/PlayerButtonRepeat.vue'
|
||||
import PlayerButtonSeekBack from '@/components/PlayerButtonSeekBack.vue'
|
||||
import PlayerButtonSeekForward from '@/components/PlayerButtonSeekForward.vue'
|
||||
import Slider from '@vueform/slider'
|
||||
import * as types from '@/store/mutation_types'
|
||||
|
||||
export default {
|
||||
@ -339,7 +336,6 @@ export default {
|
||||
components: {
|
||||
NavbarItemLink,
|
||||
NavbarItemOutput,
|
||||
Slider,
|
||||
PlayerButtonPlayPause,
|
||||
PlayerButtonNext,
|
||||
PlayerButtonPrevious,
|
||||
@ -382,9 +378,6 @@ export default {
|
||||
return ''
|
||||
},
|
||||
|
||||
state() {
|
||||
return this.$store.state.player
|
||||
},
|
||||
now_playing() {
|
||||
return this.$store.getters.now_playing
|
||||
},
|
||||
@ -427,16 +420,13 @@ export default {
|
||||
this.show_outputs_menu = false
|
||||
},
|
||||
|
||||
set_volume(newVolume) {
|
||||
webapi.player_volume(newVolume)
|
||||
change_volume() {
|
||||
webapi.player_volume(this.player.volume)
|
||||
},
|
||||
|
||||
toggle_mute_volume() {
|
||||
if (this.player.volume > 0) {
|
||||
this.set_volume(0)
|
||||
} else {
|
||||
this.set_volume(this.old_volume)
|
||||
}
|
||||
this.player.volume = this.player.volume > 0 ? 0 : this.old_volume
|
||||
this.change_volume()
|
||||
},
|
||||
|
||||
setupAudio() {
|
||||
@ -492,8 +482,8 @@ export default {
|
||||
return this.playChannel()
|
||||
},
|
||||
|
||||
set_stream_volume(newVolume) {
|
||||
this.stream_volume = newVolume
|
||||
change_stream_volume() {
|
||||
console.log(this.stream_volume)
|
||||
_audio.setVolume(this.stream_volume / 100)
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,15 @@
|
||||
:class="{ 'has-text-grey-light': !output.selected }"
|
||||
v-text="output.name"
|
||||
/>
|
||||
<Slider
|
||||
<input
|
||||
v-model="volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!output.selected"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
class="slider"
|
||||
:class="{ 'is-inactive': !output.selected }"
|
||||
max="100"
|
||||
type="range"
|
||||
:style="{ '--ratio': volume / 100 }"
|
||||
@change="change_volume"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,17 +37,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Slider from '@vueform/slider'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'NavbarItemOutput',
|
||||
components: {
|
||||
Slider
|
||||
},
|
||||
|
||||
props: ['output'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
volume: this.output.selected ? this.output.volume : 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
type_class() {
|
||||
if (this.output.type.startsWith('AirPlay')) {
|
||||
@ -59,20 +61,18 @@ export default {
|
||||
} else {
|
||||
return 'server'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
volume() {
|
||||
return this.output.selected ? this.output.volume : 0
|
||||
watch: {
|
||||
output() {
|
||||
this.volume = this.output.volume
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
play_next() {
|
||||
webapi.player_next()
|
||||
},
|
||||
|
||||
set_volume(newVolume) {
|
||||
webapi.player_output_volume(this.output.id, newVolume)
|
||||
change_volume() {
|
||||
webapi.player_output_volume(this.output.id, this.volume)
|
||||
},
|
||||
|
||||
set_enabled() {
|
||||
|
@ -12,7 +12,6 @@ import { icons } from './icons'
|
||||
import App from './App.vue'
|
||||
|
||||
import './mystyles.scss'
|
||||
import '@vueform/slider/themes/default.css'
|
||||
|
||||
const app = createApp(App)
|
||||
.use(store)
|
||||
|
@ -3,40 +3,6 @@
|
||||
@import 'bulma/bulma.sass';
|
||||
@import 'bulma-switch';
|
||||
|
||||
/* Volume slider */
|
||||
.slider {
|
||||
min-width: 250px;
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
--slider-height: 4px;
|
||||
--slider-connect-bg: #{$dark};
|
||||
--slider-tooltip-bg: #{$dark};
|
||||
--slider-handle-ring-color: #3b82f630;
|
||||
--slider-handle-shadow: 0.5px 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.32);
|
||||
--slider-handle-shadow-active: 0.5px 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
/* Now playing progress bar */
|
||||
.seek-slider {
|
||||
min-width: 250px;
|
||||
max-width: 500px;
|
||||
width: 100% !important;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
margin: 0 auto 16px auto;
|
||||
--slider-height: 4px;
|
||||
--slider-connect-bg: #{$primary};
|
||||
--slider-tooltip-bg: #{$primary};
|
||||
--slider-handle-bg: #{$primary};
|
||||
--slider-handle-border: 0;
|
||||
--slider-handle-width: 10px;
|
||||
--slider-handle-height: 10px;
|
||||
--slider-handle-radius: 9999px;
|
||||
--slider-handle-shadow: 0.5px 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.32);
|
||||
--slider-handle-shadow-active: 0.5px 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.42);
|
||||
--slider-handle-ring-width: 3px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: $info;
|
||||
border-radius: 9999px;
|
||||
@ -299,3 +265,67 @@ hr.fd-navbar-divider {
|
||||
.hero-body {
|
||||
padding: 1.5rem !important;
|
||||
}
|
||||
|
||||
/* Slider */
|
||||
@mixin thumb {
|
||||
-webkit-appearance: none;
|
||||
width: var(--th);
|
||||
height: var(--th);
|
||||
border-radius: 50%;
|
||||
background: $dark;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@mixin track {
|
||||
height: calc(var(--sh));
|
||||
border-radius: calc(var(--sh) / 2);
|
||||
background: linear-gradient(90deg, $dark var(--sx), $grey-light var(--sx));
|
||||
}
|
||||
|
||||
input[type='range'].slider {
|
||||
--sh: 0.5rem;
|
||||
--th: calc(var(--sh) * 1.5);
|
||||
--sx: calc(var(--th) / 2 + (var(--ratio) * (100% - var(--th))));
|
||||
-webkit-appearance: none;
|
||||
min-width: 250px;
|
||||
width: 100% !important;
|
||||
cursor: grab;
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
&::-webkit-slider-thumb {
|
||||
@include thumb;
|
||||
margin-top: calc((var(--th) - var(--sh)) / -2);
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
@include thumb;
|
||||
}
|
||||
&::-webkit-slider-runnable-track {
|
||||
@include track;
|
||||
}
|
||||
&::-moz-range-track {
|
||||
@include track;
|
||||
}
|
||||
&.is-inactive {
|
||||
&::-webkit-slider-thumb {
|
||||
background-color: $grey-light;
|
||||
}
|
||||
&::-webkit-slider-runnable-track {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
$grey-light var(--sx),
|
||||
$light var(--sx)
|
||||
);
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
background-color: $grey-light;
|
||||
}
|
||||
&::-moz-range-track {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
$grey-light var(--sx),
|
||||
$light var(--sx)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="section">
|
||||
<section class="section fd-page">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths has-text-centered-mobile">
|
||||
|
@ -1,69 +1,54 @@
|
||||
<template>
|
||||
<section>
|
||||
<div v-if="now_playing.id > 0" class="fd-is-fullheight">
|
||||
<cover-artwork
|
||||
:artwork_url="now_playing.artwork_url"
|
||||
:artist="now_playing.artist"
|
||||
:album="now_playing.album"
|
||||
class="is-clickable fd-has-shadow fd-is-expanded fd-cover fd-cover-big-image"
|
||||
@click="open_dialog(now_playing)"
|
||||
/>
|
||||
<div class="fd-has-padding-left-right">
|
||||
<div class="container has-text-centered">
|
||||
<p class="control has-text-centered fd-progress-now-playing">
|
||||
<slider
|
||||
ref="slider"
|
||||
v-model="item_progress_ms"
|
||||
:min="0"
|
||||
:max="state.item_length_ms"
|
||||
:step="1000"
|
||||
:tooltips="false"
|
||||
:disabled="state.state === 'stop'"
|
||||
:classes="{ target: 'seek-slider' }"
|
||||
@change="seek"
|
||||
@start="start_dragging"
|
||||
@end="end_dragging"
|
||||
/>
|
||||
</p>
|
||||
<p class="content">
|
||||
<span
|
||||
v-text="
|
||||
[
|
||||
$filters.durationInHours(item_progress_ms),
|
||||
$filters.durationInHours(now_playing.length_ms)
|
||||
].join(' / ')
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fd-has-padding-left-right">
|
||||
<div class="container has-text-centered fd-has-margin-top">
|
||||
<h1 class="title is-5" v-text="now_playing.title" />
|
||||
<h2 class="title is-6" v-text="now_playing.artist" />
|
||||
<h2
|
||||
v-if="composer"
|
||||
class="subtitle is-6 has-text-grey has-text-weight-bold"
|
||||
v-text="composer"
|
||||
<div class="hero is-fullheight">
|
||||
<div v-if="track.id > 0" class="hero-body">
|
||||
<div class="container has-text-centered" style="max-width: 500px">
|
||||
<cover-artwork
|
||||
:artwork_url="track.artwork_url"
|
||||
:artist="track.artist"
|
||||
:album="track.album"
|
||||
class="is-clickable fd-has-shadow fd-cover-big-image"
|
||||
@click="open_dialog(track)"
|
||||
/>
|
||||
<input
|
||||
v-model.number="item_progress_ms"
|
||||
:step="1000"
|
||||
:max="is_live ? 1000 : track.length_ms"
|
||||
type="range"
|
||||
class="slider mt-5"
|
||||
:style="{ '--ratio': progress }"
|
||||
@change="seek"
|
||||
@touchstart="start_dragging"
|
||||
@touchend="end_dragging"
|
||||
/>
|
||||
<div class="is-flex is-justify-content-space-between">
|
||||
<p
|
||||
class="subtitle is-7"
|
||||
v-text="$filters.durationInHours(item_progress_ms)"
|
||||
/>
|
||||
<h3 class="subtitle is-6" v-text="now_playing.album" />
|
||||
<h3
|
||||
v-if="filepath"
|
||||
class="subtitle is-6 has-text-grey"
|
||||
v-text="filepath"
|
||||
<p
|
||||
class="subtitle is-7"
|
||||
v-text="$filters.durationInHours(track.length_ms)"
|
||||
/>
|
||||
</div>
|
||||
<h1 class="title is-5" v-text="track.title" />
|
||||
<h2 class="title is-6" v-text="track.artist" />
|
||||
<h2
|
||||
v-if="composer"
|
||||
class="subtitle is-6 has-text-grey has-text-weight-bold"
|
||||
v-text="composer"
|
||||
/>
|
||||
<h3 class="subtitle is-6" v-text="track.album" />
|
||||
<h3
|
||||
v-if="filepath"
|
||||
class="subtitle is-6 has-text-grey"
|
||||
v-text="filepath"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="fd-is-fullheight">
|
||||
<div
|
||||
class="fd-is-expanded fd-has-padding-left-right"
|
||||
style="flex-direction: column"
|
||||
>
|
||||
<div class="content has-text-centered">
|
||||
<h1 class="title is-5" v-text="$t('page.now-playing.title')" />
|
||||
<p v-text="$t('page.now-playing.info')" />
|
||||
</div>
|
||||
<div v-else class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<p class="title is-5" v-text="$t('page.now-playing.title')" />
|
||||
<p class="subtitle" v-text="$t('page.now-playing.info')" />
|
||||
</div>
|
||||
</div>
|
||||
<modal-dialog-queue-item
|
||||
@ -71,12 +56,11 @@
|
||||
:item="selected_item"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||
import Slider from '@vueform/slider'
|
||||
import CoverArtwork from '@/components/CoverArtwork.vue'
|
||||
import webapi from '@/webapi'
|
||||
import * as types from '@/store/mutation_types'
|
||||
@ -85,7 +69,6 @@ export default {
|
||||
name: 'PageNowPlaying',
|
||||
components: {
|
||||
ModalDialogQueueItem,
|
||||
Slider,
|
||||
CoverArtwork
|
||||
},
|
||||
|
||||
@ -101,11 +84,19 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
state() {
|
||||
progress() {
|
||||
return this.is_live ? 2 : this.item_progress_ms / this.track.length_ms
|
||||
},
|
||||
|
||||
is_live() {
|
||||
return this.track.length_ms == 0
|
||||
},
|
||||
|
||||
player() {
|
||||
return this.$store.state.player
|
||||
},
|
||||
|
||||
now_playing() {
|
||||
track() {
|
||||
return this.$store.getters.now_playing
|
||||
},
|
||||
|
||||
@ -121,16 +112,16 @@ export default {
|
||||
if (this.settings_option_show_composer_now_playing) {
|
||||
if (
|
||||
!this.settings_option_show_composer_for_genre ||
|
||||
(this.now_playing.genre &&
|
||||
(this.track.genre &&
|
||||
this.settings_option_show_composer_for_genre
|
||||
.toLowerCase()
|
||||
.split(',')
|
||||
.findIndex(
|
||||
(elem) =>
|
||||
this.now_playing.genre.toLowerCase().indexOf(elem.trim()) >= 0
|
||||
this.track.genre.toLowerCase().indexOf(elem.trim()) >= 0
|
||||
) >= 0)
|
||||
) {
|
||||
return this.now_playing.composer
|
||||
return this.track.composer
|
||||
}
|
||||
}
|
||||
return null
|
||||
@ -142,32 +133,30 @@ export default {
|
||||
|
||||
filepath() {
|
||||
if (this.settings_option_show_filepath_now_playing) {
|
||||
return this.now_playing.path
|
||||
return this.track.path
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
state() {
|
||||
player() {
|
||||
if (this.interval_id > 0) {
|
||||
window.clearTimeout(this.interval_id)
|
||||
this.interval_id = 0
|
||||
}
|
||||
this.item_progress_ms = this.state.item_progress_ms
|
||||
if (this.state.state === 'play') {
|
||||
this.item_progress_ms = this.player.item_progress_ms
|
||||
if (this.player.state === 'play') {
|
||||
this.interval_id = window.setInterval(this.tick, 1000)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
created() {
|
||||
this.item_progress_ms = this.state.item_progress_ms
|
||||
this.item_progress_ms = this.player.item_progress_ms
|
||||
webapi.player_status().then(({ data }) => {
|
||||
this.$store.commit(types.UPDATE_PLAYER_STATUS, data)
|
||||
if (this.state.state === 'play') {
|
||||
if (this.player.state === 'play') {
|
||||
this.interval_id = window.setInterval(this.tick, 1000)
|
||||
}
|
||||
})
|
||||
@ -183,7 +172,13 @@ export default {
|
||||
methods: {
|
||||
tick() {
|
||||
if (!this.is_dragged) {
|
||||
this.item_progress_ms += 1000
|
||||
if (this.is_live) {
|
||||
this.item_progress_ms += 1000
|
||||
} else if (this.item_progress_ms + 1000 > this.track.length_ms) {
|
||||
this.item_progress_ms = this.track.length_ms
|
||||
} else {
|
||||
this.item_progress_ms += 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -195,10 +190,12 @@ export default {
|
||||
this.is_dragged = false
|
||||
},
|
||||
|
||||
seek(newPosition) {
|
||||
webapi.player_seek_to_pos(newPosition).catch(() => {
|
||||
this.item_progress_ms = this.state.item_progress_ms
|
||||
})
|
||||
seek() {
|
||||
if (!this.is_live) {
|
||||
webapi.player_seek_to_pos(this.item_progress_ms).catch(() => {
|
||||
this.item_progress_ms = this.player.item_progress_ms
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
open_dialog(item) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Search field + recent searches -->
|
||||
<section class="section pb-0">
|
||||
<section class="section fd-page pb-0">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths">
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Search field + recent searches -->
|
||||
<section class="section pb-0">
|
||||
<section class="section pb-0 fd-page">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<section class="section fd-content">
|
||||
<section class="section fd-page fd-content">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-light is-bold fd-content">
|
||||
<section class="hero is-light is-bold fd-page fd-content">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
|
Loading…
Reference in New Issue
Block a user