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