Add To... now available in all song list screens

This commit is contained in:
An Phan 2016-01-05 22:04:00 +08:00
parent 39e073a614
commit 8a7bf290f9
10 changed files with 95 additions and 228 deletions

View file

@ -67,6 +67,8 @@
if (isMobile.phone) {
this.prefs.showExtraPanel = false;
}
return true;
},
'song:play': function (song) {

View file

@ -1,5 +1,5 @@
<template>
<section id="songsWrapper">
<section id="favoritesWrapper">
<h1 class="heading">
<span>Songs You Love
<i class="fa fa-chevron-down toggler"
@ -20,6 +20,15 @@
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
<i class="fa fa-random"></i> Selected
</button>
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<add-to-menu
:songs="selectedSongs"
:showing.sync="showingAddToMenu"
:settings="{ canLike: false }">
</add-to-menu>
</div>
</h1>
@ -31,6 +40,7 @@
import isMobile from 'ismobilejs';
import songList from '../../shared/song-list.vue';
import addToMenu from '../../shared/add-to-menu.vue';
import favoriteStore from '../../../stores/favorite';
import playback from '../../../services/playback';
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
@ -38,13 +48,14 @@
export default {
mixins: [shuffleSelectedMixin],
components: { songList },
components: { songList, addToMenu },
data () {
return {
state: favoriteStore.state,
isPhone: isMobile.phone,
showingControls: false,
showingAddToMenu: false,
};
},
@ -56,6 +67,18 @@
playback.queueAndPlay(this.state.songs, true);
},
},
watch: {
/**
* Watch the number of favorite songs.
* If we don't have any, the "Add To..." menu shouldn't be left open.
*/
'state.songs': function () {
if (!this.state.songs.length) {
this.showingAddToMenu = false;
}
},
},
};
</script>
@ -63,7 +86,7 @@
@import "resources/assets/sass/partials/_vars.scss";
@import "resources/assets/sass/partials/_mixins.scss";
#songsWrapper {
#favoritesWrapper {
button.play-shuffle, button.del {
i {
margin-right: 0 !important;

View file

@ -40,6 +40,8 @@
events: {
'main-content-view:load': function (view) {
this.view = view;
return true;
},
/**
@ -86,6 +88,14 @@
z-index: 2;
@include button-group();
.add-to {
background-color: $colorGreen !important;
&:hover {
background-color: darken($colorGreen, 10%) !important;
}
}
}
input[type="search"] {

View file

@ -20,11 +20,20 @@
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
<i class="fa fa-random"></i> Selected
</button>
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<button class="del"
title="Delete this playlist"
@click.prevent="del">
<i class="fa fa-times"></i> Playlist
</button>
<add-to-menu
:songs="selectedSongs"
:showing.sync="showingAddToMenu"
:settings="{ hiddenPlaylists: [playlist] }">
</add-to-menu>
</div>
</h1>
@ -40,6 +49,7 @@
import isMobile from 'ismobilejs';
import songList from '../../shared/song-list.vue';
import addToMenu from '../../shared/add-to-menu.vue';
import playlistStore from '../../../stores/playlist';
import playback from '../../../services/playback';
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
@ -47,13 +57,14 @@
export default {
mixins: [shuffleSelectedMixin],
components: { songList },
components: { songList, addToMenu },
data() {
return {
playlist: playlistStore.stub,
isPhone: isMobile.phone,
showingControls: false,
showingAddToMenu: false,
};
},
@ -91,6 +102,18 @@
});
},
},
watch: {
/**
* Watch the number of songs in the current playlist.
* If we don't have any, the "Add To..." menu shouldn't be left open.
*/
'playlist.songs': function () {
if (!this.playlist.songs.length) {
this.showingAddToMenu = false;
}
},
},
};
</script>

View file

@ -21,18 +21,16 @@
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
<i class="fa fa-random"></i> Selected
</button>
<button class="save"
@click.prevent="showAddToPlaylistDialog = !showAddToPlaylistDialog"
v-if="state.songs.length > 1"
>
{{ showAddToPlaylistDialog ? 'Cancel' : 'Add To…' }}
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="state.songs.length > 1">
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<button class="clear" @click.prevent="clear" v-if="state.songs.length">Clear</button>
<add-to-playlist
:songs="songsToAddToPlaylist"
:showing.sync="showAddToPlaylistDialog">
</add-to-playlist>
<add-to-menu
:songs="songsToAddTo"
:showing.sync="showingAddToMenu"
:settings="{ canQueue: false }">
</add-to-menu>
</div>
</h1>
@ -45,7 +43,7 @@
import isMobile from 'ismobilejs';
import songList from '../../shared/song-list.vue';
import addToPlaylist from '../../shared/add-to-playlist.vue';
import addToMenu from '../../shared/add-to-menu.vue';
import playlistStore from '../../../stores/playlist';
import queueStore from '../../../stores/queue';
import playback from '../../../services/playback';
@ -54,12 +52,12 @@
export default {
mixins: [shuffleSelectedMixin],
components: { songList, addToPlaylist },
components: { songList, addToMenu },
data() {
return {
state: queueStore.state,
showAddToPlaylistDialog: false,
showingAddToMenu: false,
playlistName: '',
isPhone: isMobile.phone,
showingControls: false,
@ -72,7 +70,7 @@
*
* @return {Array} The songs to add into a (new) playlist
*/
songsToAddToPlaylist() {
songsToAddTo() {
return this.selectedSongs.length ? this.selectedSongs : queueStore.all();
},
},
@ -80,11 +78,11 @@
watch: {
/**
* Watch the number of songs currently queued.
* If we don't have any queuing song, the "Save to Playlist" form shouldn't be open.
* If we don't have any queuing song, the "Add To..." menu shouldn't be left open.
*/
'state.songs': function () {
if (!queueStore.all().length) {
this.showAddToPlaylist = false;
this.showingAddToMenu = false;
}
},
},

View file

@ -22,17 +22,14 @@
<i class="fa fa-random"></i> Selected
</button>
<button class="save"
@click.prevent="showAddToPlaylistDialog = !showAddToPlaylistDialog"
v-if="selectedSongs.length > 0"
>
{{ showAddToPlaylistDialog ? 'Cancel' : 'Add To…' }}
<button class="add-to" @click.prevent="showingAddToMenu = !showingAddToMenu" v-if="selectedSongs.length">
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</button>
<add-to-playlist
<add-to-menu
:songs="selectedSongs"
:showing.sync="showAddToPlaylistDialog">
</add-to-playlist>
:showing.sync="showingAddToMenu">
</add-to-menu>
</div>
</h1>
@ -44,7 +41,7 @@
import isMobile from 'ismobilejs';
import songList from '../../shared/song-list.vue';
import addToPlaylist from '../../shared/add-to-playlist.vue';
import addToMenu from '../../shared/add-to-menu.vue';
import songStore from '../../../stores/song';
import playback from '../../../services/playback';
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
@ -52,14 +49,14 @@
export default {
mixins: [shuffleSelectedMixin],
components: { songList, addToPlaylist },
components: { songList, addToMenu },
data() {
return {
state: songStore.state,
isPhone: isMobile.phone,
showingControls: false,
showAddToPlaylistDialog: false,
showingAddToMenu: false,
};
},
@ -84,16 +81,6 @@
color: $color2ndText;
margin-top: 16px;
}
button.save {
background-color: $colorGreen !important;
&:hover {
background-color: darken($colorGreen, 10%) !important;
}
}
}
</style>

View file

@ -128,6 +128,8 @@
if (isMobile.phone) {
this.showing = false;
}
return true;
},
/**

View file

@ -1,188 +0,0 @@
<template>
<div class="add-to-playlist" v-show="showing">
<p>Add {{ songs.length }} song{{ songs.length > 1 ? 's' : '' }} into</p>
<ul>
<li v-if="this._settings.canLike" @click="addSongsToFavorite">Favorites</li>
<template v-for="playlist in playlistState.playlists">
<li v-hide="isPlaylistHidden(playlist)" @click="addSongsToExisting(playlist)">{{ playlist.name }}</li>
</template>
</ul>
<p>or create a new playlist</p>
<form class="form-save form-simple" @submit.prevent="createNewFromSongs">
<input type="text"
@keyup.esc.prevent="showing = false"
v-model="newPlaylistName"
placeholder="Playlist name"
required>
<button type="submit"><i class="fa fa-save"></i></button>
</form>
</div>
</template>
<script>
import _ from 'lodash';
import playlistStore from '../../stores/playlist';
import favoriteStore from '../../stores/favorite';
export default {
props: ['songs', 'showing', 'settings'],
data() {
return {
newPlaylistName: '',
playlistState: playlistStore.state,
_settings: _.assign({
canQueue: true,
canLike: true,
hiddenPlaylists: []
}, this.settings),
}
},
watch: {
songs() {
if (!this.songs.length) {
this.showing = false;
}
},
},
methods: {
/**
* Determine if a playlist should be hidden from the menu.
*
* @param {Object} playlist
*
* @return {Boolean}
*/
isPlaylistHidden(playlist) {
return _.contains(this._settings.hiddenPlaylists, playlist);
},
/**
* Add the selected songs into Favorite.
*/
addSongsToFavorite() {
this.showing = false;
favoriteStore.like(this.songs, () => {
// Nothing much now.
});
},
/**
* Add the selected songs into the chosen playlist.
*
* @param {Object} playlist The playlist.
*/
addSongsToExisting(playlist) {
this.showing = false;
playlistStore.addSongs(playlist, this.songs, () => {
// Nothing much now.
});
},
/**
* Save the selected songs as a playlist.
* As of current we don't have selective save.
*/
createNewFromSongs() {
this.newPlaylistName = this.newPlaylistName.trim();
if (!this.newPlaylistName) {
return;
}
this.showing = false;
playlistStore.store(this.newPlaylistName, this.songs, () => {
this.newPlaylistName = '';
});
},
},
};
</script>
<style lang="sass" scoped>
@import "resources/assets/sass/partials/_vars.scss";
@import "resources/assets/sass/partials/_mixins.scss";
.add-to-playlist {
@include context-menu();
position: absolute;
top: 36px;
left: 0;
width: 100%;
p {
margin: 4px 0;
font-size: 90%;
&::first-of-type {
margin-top: 0;
}
}
$itemHeight: 28px;
$itemMargin: 2px;
ul {
max-height: 5 * ($itemHeight + $itemMargin);
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
li {
cursor: pointer;
background: rgba(255, 255, 255, .2);
height: $itemHeight;
line-height: $itemHeight;
padding: 0 8px;
margin: $itemMargin 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-radius: 3px;
background: #fff;
&:hover {
background: $colorHighlight;
color: #fff;
}
}
&::before {
display: block;
content: " ";
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid rgb(232, 232, 232);
position: absolute;
top: -7px;
left: calc(50% - 10px);
}
form {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
input[type="text"] {
width: 100%;
border-radius: 5px 0 0 5px;
height: 28px;
}
button[type="submit"] {
margin-top: 0;
border-radius: 0 5px 5px 0 !important;
height: 28px;
margin-left: -2px !important;
}
}
}
</style>

View file

@ -297,6 +297,7 @@
},
clearSelection() {
this.selectedSongs = [];
$('.song-item').removeClass('selected');
},
@ -376,6 +377,13 @@
'filter:changed': function (q) {
this.q = q;
},
/**
* Clears the current list's selection if the user has switched to another view.
*/
'main-content-view:load': function () {
this.clearSelection();
},
},
};
</script>

View file

@ -264,6 +264,8 @@
*/
'main-content-view:load': function (view) {
this.viewingQueue = view === 'queue';
return true;
},
'koel:teardown': function () {