diff --git a/changes/changelog.d/866.enhancement b/changes/changelog.d/866.enhancement new file mode 100644 index 0000000000000000000000000000000000000000..9ebbd52dddd69aab088759f27c8f6462a5bd3852 --- /dev/null +++ b/changes/changelog.d/866.enhancement @@ -0,0 +1 @@ +New keyboard shortcuts added for enhanced control over audio player (#866) \ No newline at end of file diff --git a/front/src/components/ShortcutsModal.vue b/front/src/components/ShortcutsModal.vue index 5b1a7349d441a0de9c708f2ab9dbc03f576ab98e..06fb25ba4b2c6691cf188902c09c74aeb4abda97 100644 --- a/front/src/components/ShortcutsModal.vue +++ b/front/src/components/ShortcutsModal.vue @@ -4,18 +4,36 @@ <translate translate-context="*/*/*/Noun">Keyboard shortcuts</translate> </header> <section class="scrolling content"> - <table - class="ui compact collapsing basic table" - v-for="section in sections" - :key="section.title"> - <caption>{{ section.title }}</caption> - <tbody> - <tr v-for="shortcut in section.shortcuts" :key="shortcut.summary"> - <td>{{ shortcut.summary }}</td> - <td><span class="ui label">{{ shortcut.key }}</span></td> - </tr> - </tbody> - </table> + <div class="ui stackable two column grid"> + <div class="column"> + <table + class="ui compact basic table" + v-for="section in player" + :key="section.title"> + <caption>{{ section.title }}</caption> + <tbody> + <tr v-for="shortcut in section.shortcuts" :key="shortcut.summary"> + <td>{{ shortcut.summary }}</td> + <td><span class="ui label">{{ shortcut.key }}</span></td> + </tr> + </tbody> + </table> + </div> + <div class="column"> + <table + class="ui compact basic table" + v-for="section in general" + :key="section.title"> + <caption>{{ section.title }}</caption> + <tbody> + <tr v-for="shortcut in section.shortcuts" :key="shortcut.summary"> + <td>{{ shortcut.summary }}</td> + <td><span class="ui label">{{ shortcut.key }}</span></td> + </tr> + </tbody> + </table> + </div> + </div> </section> <footer class="actions"> <div class="ui cancel button"><translate translate-context="Popup/Keyboard shortcuts/Button.Label/Verb">Close</translate></div> @@ -32,7 +50,7 @@ export default { Modal, }, computed: { - sections () { + general () { return [ { title: this.$pgettext('Popup/Keyboard shortcuts/Title', 'General shortcuts'), @@ -40,17 +58,36 @@ export default { { key: 'h', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Show available keyboard shortcuts') - } + }, + { + key: 'shift + f', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Focus searchbar') + }, + { + key: 'esc', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Unfocus searchbar') + }, ] }, + ] + }, // space.prevent.exact="togglePlay" - // ctrl.left.prevent.exact="previous" - // ctrl.right.prevent.exact="next" - // ctrl.down.prevent.exact="$store.commit('player/incrementVolume', -0.1)" - // ctrl.up.prevent.exact="$store.commit('player/incrementVolume', 0.1)" + // ctrl.shift.left.prevent.exact="previous" + // ctrl.shift.right.prevent.exact="next" + // shift.down.prevent.exact="$store.commit('player/incrementVolume', -0.1)" + // shift.up.prevent.exact="$store.commit('player/incrementVolume', 0.1)" + // right.prevent.exact="seek (5)" + // left.prevent.exact="seek (-5)" + // shift.right.prevent.exact="seek (30)" + // shift.left.prevent.exact="seek (-30)" + // m.prevent.exact="toggleMute" // l.prevent.exact="$store.commit('player/toggleLooping')" // s.prevent.exact="shuffle" + // f.prevent.exact="$store.dispatch('favorites/toggle', currentTrack.id)" + // q.prevent.exact="clean" + player () { + return [ { title: this.$pgettext('Popup/Keyboard shortcuts/Title', 'Audio player shortcuts'), shortcuts: [ @@ -59,21 +96,41 @@ export default { summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Pause/play the current track') }, { - key: 'ctrl left', + key: 'left', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Seek backwards 5s') + }, + { + key: 'right', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Seek forwards 5s') + }, + { + key: 'shift + left', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Seek backwards 30s') + }, + { + key: 'shift + right', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Seek forwards 30s') + }, + { + key: 'ctrl + shift + left', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Play previous track') }, { - key: 'ctrl right', + key: 'ctrl + shift + right', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Play next track') }, { - key: 'ctrl up', + key: 'shift + up', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Increase volume') }, { - key: 'ctrl down', + key: 'shift + down', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Decrease volume') }, + { + key: 'm', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Toggle mute') + }, { key: 'l', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Toggle queue looping') @@ -82,6 +139,14 @@ export default { key: 's', summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Shuffle queue') }, + { + key: 'q', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Clear queue') + }, + { + key: 'f', + summary: this.$pgettext('Popup/Keyboard shortcuts/Table.Label/Verb', 'Toggle favorite') + }, ] } ] diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue index 8faaf670c00a736637be8f9a7b767d6deef6ce82..032be232deaf6ebda27d4b3c88970b4e904ea24d 100644 --- a/front/src/components/audio/Player.vue +++ b/front/src/components/audio/Player.vue @@ -206,12 +206,19 @@ </div> <GlobalEvents @keydown.space.prevent.exact="togglePlay" - @keydown.ctrl.left.prevent.exact="previous" - @keydown.ctrl.right.prevent.exact="next" - @keydown.ctrl.down.prevent.exact="$store.commit('player/incrementVolume', -0.1)" - @keydown.ctrl.up.prevent.exact="$store.commit('player/incrementVolume', 0.1)" + @keydown.ctrl.shift.left.prevent.exact="previous" + @keydown.ctrl.shift.right.prevent.exact="next" + @keydown.shift.down.prevent.exact="$store.commit('player/incrementVolume', -0.1)" + @keydown.shift.up.prevent.exact="$store.commit('player/incrementVolume', 0.1)" + @keydown.right.prevent.exact="seek (5)" + @keydown.left.prevent.exact="seek (-5)" + @keydown.shift.right.prevent.exact="seek (30)" + @keydown.shift.left.prevent.exact="seek (-30)" + @keydown.m.prevent.exact="toggleMute" @keydown.l.prevent.exact="$store.commit('player/toggleLooping')" @keydown.s.prevent.exact="shuffle" + @keydown.f.prevent.exact="$store.dispatch('favorites/toggle', currentTrack.id)" + @keydown.q.prevent.exact="clean" /> </div> </section> @@ -294,6 +301,7 @@ export default { mute: "player/mute", unmute: "player/unmute", clean: "queue/clean", + toggleMute: "player/toggleMute", }), async getTrackData (trackData) { let data = null @@ -489,6 +497,21 @@ export default { } } }, + seek (step) { + if (step > 0) { + // seek right + if (this.currentTime + step < this.duration) { + this.$store.dispatch('player/updateProgress', (this.currentTime + step)) + } else { + this.next() // parenthesis where missing here + } + } + else { + // seek left + let position = Math.max(this.currentTime + step, 0) + this.$store.dispatch('player/updateProgress', position) + } + }, observeProgress: function (enable) { let self = this if (enable) { diff --git a/front/src/components/audio/SearchBar.vue b/front/src/components/audio/SearchBar.vue index 28b11b040d19dec5832cd5eb44971fd0e3a9b764..998a668eccd3c0506d0bd0eb42478c6237b23c00 100644 --- a/front/src/components/audio/SearchBar.vue +++ b/front/src/components/audio/SearchBar.vue @@ -1,19 +1,26 @@ <template> <div class="ui fluid category search"> <slot></slot><div class="ui icon input"> - <input class="prompt" name="search" :placeholder="labels.placeholder" type="text"> + <input class="prompt" ref="search" name="search" :placeholder="labels.placeholder" type="text" @keydown.esc="$event.target.blur()"> <i class="search icon"></i> </div> <div class="results"></div> <slot name="after"></slot> + <GlobalEvents + @keydown.shift.f.prevent.exact="focusSearch" + /> </div> </template> <script> import jQuery from 'jquery' import router from '@/router' +import GlobalEvents from "@/components/utils/global-events" export default { + components: { + GlobalEvents, + }, computed: { labels () { return { @@ -104,6 +111,11 @@ export default { url: this.$store.getters['instance/absoluteUrl']('api/v1/search?query={query}') } }) + }, + methods: { + focusSearch () { + this.$refs.search.focus() + }, } } </script> diff --git a/front/src/store/player.js b/front/src/store/player.js index fac17368d10377b959fb98520f242eb2f77f4aa2..6757f0beef1e04655c60a366a844d3f10d179638 100644 --- a/front/src/store/player.js +++ b/front/src/store/player.js @@ -109,6 +109,15 @@ export default { }, 3000) } }, + toggleMute({commit, state}) { + if (state.volume > 0) { + commit('tempVolume', state.volume) + commit('volume', 0) + } + else { + commit('volume', state.tempVolume) + } + }, trackListened ({commit, rootState}, track) { if (!rootState.auth.authenticated) { return