music.mpd vue.js refactoring WIP: Implemented playlist track move feature

This commit is contained in:
Fabio Manganiello 2019-06-04 15:59:07 +02:00
parent d3ecb7b871
commit 611a137ff6
7 changed files with 74 additions and 24 deletions

View file

@ -132,6 +132,13 @@
height: 4rem; height: 4rem;
@include animation(active-track 5s infinite); @include animation(active-track 5s infinite);
} }
&.move:hover {
background: $move-mode-track-bg !important;
border-top: $move-mode-track-border;
border-bottom: $move-mode-track-border;
cursor: move;
}
} }
} }
} }

View file

@ -23,3 +23,6 @@ $playlist-controls-border: $default-border-2;
$active-track-bg-1: #d4ffe3; $active-track-bg-1: #d4ffe3;
$active-track-bg-2: #9cdfb0; $active-track-bg-2: #9cdfb0;
$move-mode-track-border: 3px dotted rgb(216,156,136);
$move-mode-track-bg: rgba(216,156,136,0.3);

View file

@ -17,6 +17,11 @@ Vue.component('music-mpd', {
browser: false, browser: false,
}, },
moveMode: {
playlist: false,
editor: false,
},
selectedPlaylistItems: {}, selectedPlaylistItems: {},
selectedBrowserItems: {}, selectedBrowserItems: {},
@ -45,24 +50,29 @@ Vue.component('music-mpd', {
}); });
} }
items.push( items.push({
{
text: 'Add to playlist', text: 'Add to playlist',
icon: 'list', icon: 'list',
}, });
{
if (Object.keys(this.selectedPlaylistItems).length < this.playlist.length) {
items.push({
text: 'Move', text: 'Move',
icon: 'retweet', icon: 'retweet',
click: function() {
self.moveMode.playlist = true;
}, },
{ });
}
items.push({
text: 'Remove from queue', text: 'Remove from queue',
icon: 'trash', icon: 'trash',
click: async function() { click: async function() {
await self.del(); await self.del();
self.selectedPlaylistItems = {}; self.selectedPlaylistItems = {};
}, },
}, });
);
if (Object.keys(this.selectedPlaylistItems).length === 1) { if (Object.keys(this.selectedPlaylistItems).length === 1) {
items.push({ items.push({
@ -473,10 +483,8 @@ Vue.component('music-mpd', {
this._parsePlaylist(playlist); this._parsePlaylist(playlist);
}, },
load: async function(item) { load: async function(item, play=false) {
let status = await request('music.mpd.load', {playlist:item}); await request('music.mpd.load', {playlist:item, play:play});
this._parseStatus(status);
let playlist = await request('music.mpd.playlistinfo'); let playlist = await request('music.mpd.playlistinfo');
this._parsePlaylist(playlist); this._parsePlaylist(playlist);
}, },
@ -511,6 +519,16 @@ Vue.component('music-mpd', {
this._parseBrowserItems(items); this._parseBrowserItems(items);
}, },
move: async function(fromPos, toPos, updateChanges=true) {
let status = await request('music.mpd.move', {from_pos: fromPos, to_pos: toPos});
if (updateChanges) {
this._parseStatus(status);
const playlist = await request('music.mpd.playlistinfo');
this._parsePlaylist(playlist);
}
},
swap: async function() { swap: async function() {
if (Object.keys(this.selectedPlaylistItems).length !== 2) { if (Object.keys(this.selectedPlaylistItems).length !== 2) {
return; return;
@ -693,13 +711,24 @@ Vue.component('music-mpd', {
this.browserFilter.toLocaleLowerCase().split(' ').filter(_ => _.length > 0).join(' ')) >= 0; this.browserFilter.toLocaleLowerCase().split(' ').filter(_ => _.length > 0).join(' ')) >= 0;
}, },
onPlaylistItemClick: function(track) { onPlaylistItemClick: async function(track) {
if (this.selectionMode.playlist) { if (this.selectionMode.playlist) {
if (track.pos in this.selectedPlaylistItems) { if (track.pos in this.selectedPlaylistItems) {
Vue.delete(this.selectedPlaylistItems, track.pos); Vue.delete(this.selectedPlaylistItems, track.pos);
} else { } else {
Vue.set(this.selectedPlaylistItems, track.pos, track); Vue.set(this.selectedPlaylistItems, track.pos, track);
} }
} else if (this.moveMode.playlist) {
var fromPos = Object.values(this.selectedPlaylistItems).map(_ => _.pos);
var toPos = track.pos;
this.moveMode.playlist = false;
const promises = fromPos.map((pos,i) => this.move(pos, toPos+i, false));
await Promise.all(promises);
this.selectedPlaylistItems = {};
const playlist = await request('music.mpd.playlistinfo');
this._parsePlaylist(playlist);
} else if (track.pos in this.selectedPlaylistItems) { } else if (track.pos in this.selectedPlaylistItems) {
Vue.delete(this.selectedPlaylistItems, track.pos); Vue.delete(this.selectedPlaylistItems, track.pos);
} else { } else {

View file

@ -15,6 +15,11 @@ Vue.component('music-mpd-playlist-item', {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
move: {
type: Boolean,
default: false,
},
}, },
}); });

View file

@ -120,6 +120,7 @@
:track="item" :track="item"
:active="track.file && status.state !== 'stop' && item.file === track.file" :active="track.file && status.state !== 'stop' && item.file === track.file"
:selected="item.pos in selectedPlaylistItems" :selected="item.pos in selectedPlaylistItems"
:move="moveMode.playlist"
:ref="track.file && status.state !== 'stop' && item.file === track.file ? 'activePlaylistTrack' : undefined" :ref="track.file && status.state !== 'stop' && item.file === track.file ? 'activePlaylistTrack' : undefined"
@input="onPlaylistItemClick"> @input="onPlaylistItemClick">
</music-mpd-playlist-item> </music-mpd-playlist-item>
@ -167,7 +168,7 @@
<div class="col-3 pull-right"> <div class="col-3 pull-right">
<div class="row"> <div class="row">
<button @click="single" :class="{enabled: status.single}" title="Toggle single mode"> <button @click="single" :class="{enabled: status.single}" title="Toggle single mode">
<i class="fa fa-chess-pawn"></i> <i class="fa fa-bullseye"></i>
</button> </button>
<button @click="consume" :class="{enabled: status.consume}" title="Toggle consume mode"> <button @click="consume" :class="{enabled: status.consume}" title="Toggle consume mode">
<i class="fa fa-utensils"></i> <i class="fa fa-utensils"></i>

View file

@ -2,7 +2,7 @@
<script type="text/x-template" id="tmpl-music-mpd-playlist-item"> <script type="text/x-template" id="tmpl-music-mpd-playlist-item">
<div class="row item playlist-item" <div class="row item playlist-item"
:class="{selected: selected, active: active}" :class="{selected: selected, active: active, move: move}"
@click="$emit('input', track)"> @click="$emit('input', track)">
<div class="col-5 artist" v-text="track.artist"></div> <div class="col-5 artist" v-text="track.artist"></div>
<div class="col-5 title" v-text="track.title"></div> <div class="col-5 title" v-text="track.title"></div>

View file

@ -379,16 +379,21 @@ class MusicMpdPlugin(MusicPlugin):
return resource return resource
@action @action
def load(self, playlist): def load(self, playlist, play=True):
""" """
Load and play a playlist by name Load and play a playlist by name
:param playlist: Playlist name :param playlist: Playlist name
:type playlist: str :type playlist: str
:param play: Start playback after loading the playlist (default: True)
:type play: bool
""" """
self._exec('load', playlist) ret = self._exec('load', playlist)
return self.play() if play:
self.play()
return ret
@action @action
def clear(self): def clear(self):