mirror of
https://github.com/koel/koel
synced 2024-11-24 05:03:05 +00:00
Fixes #4
This commit is contained in:
parent
73802d4584
commit
957505e4a4
10 changed files with 97 additions and 20 deletions
12
browserconfig.xml
Normal file
12
browserconfig.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Please read: https://msdn.microsoft.com/en-us/library/ie/dn455106.aspx -->
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square70x70logo src="public/img/tile.png"/>
|
||||||
|
<square150x150logo src="public/img/tile.png"/>
|
||||||
|
<wide310x150logo src="public/img/tile-wide.png"/>
|
||||||
|
<square310x310logo src="public/img/tile.png"/>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
BIN
resources/assets/img/apple-touch-icon-precomposed.png
Normal file
BIN
resources/assets/img/apple-touch-icon-precomposed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/assets/img/tile-wide.png
Executable file
BIN
resources/assets/img/tile-wide.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
BIN
resources/assets/img/tile.png
Executable file
BIN
resources/assets/img/tile.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
|
@ -13,14 +13,17 @@
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle"
|
<button class="play-shuffle"
|
||||||
@click.prevent="shuffle"
|
@click.prevent="shuffle"
|
||||||
v-if="state.songs.length"
|
v-if="state.songs.length && selectedSongs.length < 2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-random"></i> All
|
<i class="fa fa-random"></i> All
|
||||||
</button>
|
</button>
|
||||||
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
|
<i class="fa fa-random"></i> Selected
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list :items="state.songs" type="favorites"></song-list>
|
<song-list :items="state.songs" :selected-songs.sync="selectedSongs" type="favorites"></song-list>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -30,8 +33,11 @@
|
||||||
import songList from '../../shared/song-list.vue';
|
import songList from '../../shared/song-list.vue';
|
||||||
import favoriteStore from '../../../stores/favorite';
|
import favoriteStore from '../../../stores/favorite';
|
||||||
import playback from '../../../services/playback';
|
import playback from '../../../services/playback';
|
||||||
|
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [shuffleSelectedMixin],
|
||||||
|
|
||||||
components: { songList },
|
components: { songList },
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
|
|
|
@ -13,10 +13,13 @@
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle"
|
<button class="play-shuffle"
|
||||||
@click.prevent="shuffle"
|
@click.prevent="shuffle"
|
||||||
v-if="playlist.songs.length"
|
v-if="playlist.songs.length && selectedSongs.length < 2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-random"></i> All
|
<i class="fa fa-random"></i> All
|
||||||
</button>
|
</button>
|
||||||
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
|
<i class="fa fa-random"></i> Selected
|
||||||
|
</button>
|
||||||
<button class="del"
|
<button class="del"
|
||||||
title="Delete this playlist"
|
title="Delete this playlist"
|
||||||
@click.prevent="del">
|
@click.prevent="del">
|
||||||
|
@ -25,7 +28,11 @@
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list :items="playlist.songs" type="playlist" :playlist="playlist"></song-list>
|
<song-list :items="playlist.songs"
|
||||||
|
:selected-songs.sync="selectedSongs"
|
||||||
|
type="playlist"
|
||||||
|
:playlist="playlist">
|
||||||
|
</song-list>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -35,8 +42,11 @@
|
||||||
import songList from '../../shared/song-list.vue';
|
import songList from '../../shared/song-list.vue';
|
||||||
import playlistStore from '../../../stores/playlist';
|
import playlistStore from '../../../stores/playlist';
|
||||||
import playback from '../../../services/playback';
|
import playback from '../../../services/playback';
|
||||||
|
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [shuffleSelectedMixin],
|
||||||
|
|
||||||
components: { songList },
|
components: { songList },
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -11,9 +11,16 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle" @click.prevent="shuffle" v-if="state.songs.length > 1">
|
<button
|
||||||
|
class="play-shuffle"
|
||||||
|
@click.prevent="shuffle"
|
||||||
|
v-if="state.songs.length > 1 && selectedSongs.length < 2"
|
||||||
|
>
|
||||||
<i class="fa fa-random"></i> All
|
<i class="fa fa-random"></i> All
|
||||||
</button>
|
</button>
|
||||||
|
<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="saving = !saving" v-if="state.songs.length > 1">
|
<button class="save" @click.prevent="saving = !saving" v-if="state.songs.length > 1">
|
||||||
{{ saving ? 'Cancel' : 'Save' }}
|
{{ saving ? 'Cancel' : 'Save' }}
|
||||||
</button>
|
</button>
|
||||||
|
@ -31,7 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list :items="state.songs" type="queue"></song-list>
|
<song-list :items="state.songs" :selected-songs.sync="selectedSongs" type="queue"></song-list>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -43,8 +50,11 @@
|
||||||
import playlistStore from '../../../stores/playlist';
|
import playlistStore from '../../../stores/playlist';
|
||||||
import queueStore from '../../../stores/queue';
|
import queueStore from '../../../stores/queue';
|
||||||
import playback from '../../../services/playback';
|
import playback from '../../../services/playback';
|
||||||
|
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [shuffleSelectedMixin],
|
||||||
|
|
||||||
components: { songList },
|
components: { songList },
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -11,13 +11,20 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="buttons" v-show="!isPhone || showingControls">
|
<div class="buttons" v-show="!isPhone || showingControls">
|
||||||
<button class="play-shuffle" @click.prevent="shuffle" v-if="state.songs.length">
|
<button
|
||||||
|
class="play-shuffle"
|
||||||
|
@click.prevent="shuffle"
|
||||||
|
v-if="state.songs.length && selectedSongs.length < 2"
|
||||||
|
>
|
||||||
<i class="fa fa-random"></i> All
|
<i class="fa fa-random"></i> All
|
||||||
</button>
|
</button>
|
||||||
|
<button class="play-shuffle" @click.prevent="shuffleSelected" v-if="selectedSongs.length > 1">
|
||||||
|
<i class="fa fa-random"></i> Selected
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<song-list :items="state.songs"></song-list>
|
<song-list :items="state.songs" :selected-songs.sync="selectedSongs"></song-list>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -27,8 +34,11 @@
|
||||||
import songList from '../../shared/song-list.vue';
|
import songList from '../../shared/song-list.vue';
|
||||||
import songStore from '../../../stores/song';
|
import songStore from '../../../stores/song';
|
||||||
import playback from '../../../services/playback';
|
import playback from '../../../services/playback';
|
||||||
|
import shuffleSelectedMixin from '../../../mixins/shuffle-selected';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [shuffleSelectedMixin],
|
||||||
|
|
||||||
components: { songList },
|
components: { songList },
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
import playback from '../../services/playback';
|
import playback from '../../services/playback';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['items', 'type', 'playlist'],
|
props: ['items', 'type', 'playlist', 'selectedSongs'],
|
||||||
mixins: [infiniteScroll],
|
mixins: [infiniteScroll],
|
||||||
components: { songItem },
|
components: { songItem },
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
* Execute the corresponding reaction(s) when the user presses Delete.
|
* Execute the corresponding reaction(s) when the user presses Delete.
|
||||||
*/
|
*/
|
||||||
handleDelete() {
|
handleDelete() {
|
||||||
var songs = this.getSelectedSongs();
|
var songs = this.selectedSongs;
|
||||||
|
|
||||||
if (!songs.length) {
|
if (!songs.length) {
|
||||||
return;
|
return;
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
* Execute the corresponding reaction(s) when the user presses Enter.
|
* Execute the corresponding reaction(s) when the user presses Enter.
|
||||||
*/
|
*/
|
||||||
handleEnter(e) {
|
handleEnter(e) {
|
||||||
var songs = this.getSelectedSongs();
|
var songs = this.selectedSongs;
|
||||||
|
|
||||||
if (!songs.length) {
|
if (!songs.length) {
|
||||||
return;
|
return;
|
||||||
|
@ -229,21 +229,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this.$els.wrapper).find('.song-item').addClass('selected');
|
$(this.$els.wrapper).find('.song-item').addClass('selected');
|
||||||
|
this.gatherSelected();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currerntly selected songs.
|
* Gather all selected songs
|
||||||
*
|
*
|
||||||
* @return array An array of Song objects.
|
* @return array An array of Song object
|
||||||
*/
|
*/
|
||||||
getSelectedSongs() {
|
gatherSelected() {
|
||||||
var songs = [];
|
var ids = _.map($(this.$els.wrapper).find('.song-item.selected'), row => {
|
||||||
|
return $(row).data('song-id');
|
||||||
_.each($(this.$els.wrapper).find('.song-item.selected'), row => {
|
|
||||||
songs.push(songStore.byId($(row).data('song-id')));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return songs;
|
this.selectedSongs = songStore.byIds(ids);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,6 +279,8 @@
|
||||||
this.selectRowsBetweenIndexes([this.lastSelectedRow.rowIndex, row.rowIndex])
|
this.selectRowsBetweenIndexes([this.lastSelectedRow.rowIndex, row.rowIndex])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.gatherSelected();
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleRow(row) {
|
toggleRow(row) {
|
||||||
|
@ -312,7 +313,7 @@
|
||||||
|
|
||||||
// We can opt for something like application/x-koel.text+plain here to sound fancy,
|
// We can opt for something like application/x-koel.text+plain here to sound fancy,
|
||||||
// but forget it.
|
// but forget it.
|
||||||
e.dataTransfer.setData('text/plain', _.pluck(this.getSelectedSongs(), 'id'));
|
e.dataTransfer.setData('text/plain', _.pluck(this.selectedSongs, 'id'));
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
|
||||||
// Set a fancy icon
|
// Set a fancy icon
|
||||||
|
|
28
resources/assets/js/mixins/shuffle-selected.js
Normal file
28
resources/assets/js/mixins/shuffle-selected.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
import playback from '../services/playback';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a "shuffle selected" functionality to any component containing a song-list component using this mixin.
|
||||||
|
* Such a component should:
|
||||||
|
* - pass "selectedSongs" SYNC prop into the song-list component, e.g.
|
||||||
|
* <song-list :items="state.songs" :selected-songs.sync="selectedSongs" type="queue"></song-list>
|
||||||
|
* - trigger shuffling with shuffleSelected() method
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedSongs: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
shuffleSelected() {
|
||||||
|
if (this.selectedSongs.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
playback.queueAndPlay(this.selectedSongs, true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
Loading…
Reference in a new issue