Further refactoring of the queue controller and view
- Removes queue-related functions from the main controller. They are now handled by queue.js, which delegates them to player-service.js - Fixes problem in scrobbling. A song is no longer scrobbled every time it is paused. A song will not be scrobbled upon loading, only while it is playing. - Moves the entire html for the sidebar queue to queue.html. It replaces a template that was no longer used. - Most queue-related functions in player return player itself to make them chainable just like in jQuery, e.g. : player.shuffleQueue().playFirstSong();
This commit is contained in:
parent
83869b7808
commit
c787c468b9
12 changed files with 85 additions and 89 deletions
|
@ -304,18 +304,11 @@ angular.module('JamStash')
|
||||||
notifications.updateMessage($scope.selectedSongs.length + ' Song(s) Added to Queue', true);
|
notifications.updateMessage($scope.selectedSongs.length + ' Song(s) Added to Queue', true);
|
||||||
$scope.selectedSongs.length = 0;
|
$scope.selectedSongs.length = 0;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
$scope.addSongToQueue = function (data) {
|
|
||||||
$rootScope.queue.push(data);
|
|
||||||
};
|
};
|
||||||
$rootScope.removeSong = function (item, songs) {
|
$rootScope.removeSong = function (item, songs) {
|
||||||
var index = songs.indexOf(item);
|
var index = songs.indexOf(item);
|
||||||
songs.splice(index, 1);
|
songs.splice(index, 1);
|
||||||
};
|
};
|
||||||
$scope.removeSongFromQueue = function (item) {
|
|
||||||
var index = $rootScope.queue.indexOf(item)
|
|
||||||
$rootScope.queue.splice(index, 1);
|
|
||||||
};
|
|
||||||
$scope.isActive = function (route) {
|
$scope.isActive = function (route) {
|
||||||
return route === $location.path();
|
return route === $location.path();
|
||||||
};
|
};
|
||||||
|
@ -344,20 +337,6 @@ angular.module('JamStash')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$scope.queueRemoveSelected = function (data, event) {
|
|
||||||
angular.forEach($scope.selectedSongs, function (item, key) {
|
|
||||||
var index = $rootScope.queue.indexOf(item);
|
|
||||||
if (index > -1) {
|
|
||||||
$rootScope.queue.splice(index, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
$scope.queueEmpty = function () {
|
|
||||||
//TODO: Hyz: Remove
|
|
||||||
//self.selectedSongs([]);
|
|
||||||
$rootScope.queue = [];
|
|
||||||
$.fancybox.close();
|
|
||||||
};
|
|
||||||
$scope.queueTotal = function () {
|
$scope.queueTotal = function () {
|
||||||
var total = 0;
|
var total = 0;
|
||||||
utils.arrayForEach(self.queue(), function (item) {
|
utils.arrayForEach(self.queue(), function (item) {
|
||||||
|
@ -369,10 +348,6 @@ angular.module('JamStash')
|
||||||
return '0 song(s), 00:00:00 total time';
|
return '0 song(s), 00:00:00 total time';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$scope.queueShuffle = function () {
|
|
||||||
//TODO: Hyz: Remove
|
|
||||||
$rootScope.queue.sort(function () { return 0.5 - Math.random(); });
|
|
||||||
};
|
|
||||||
$scope.selectedSongs = [];
|
$scope.selectedSongs = [];
|
||||||
$scope.selectSong = function (data) {
|
$scope.selectSong = function (data) {
|
||||||
var i = $scope.selectedSongs.indexOf(data);
|
var i = $scope.selectedSongs.indexOf(data);
|
||||||
|
@ -412,11 +387,6 @@ angular.module('JamStash')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Hyz: I don't know yet how to remove the circular dependency between player-service
|
|
||||||
// and notification-service... So I'll keep this one there until I know.
|
|
||||||
$rootScope.nextTrack = function (loadonly, song) {
|
|
||||||
player.nextTrack(loadonly, song);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.updateFavorite = function (item) {
|
$scope.updateFavorite = function (item) {
|
||||||
var id = item.id;
|
var id = item.id;
|
||||||
|
|
|
@ -66,7 +66,6 @@ describe("Main controller", function() {
|
||||||
spyOn(locker, "get").and.callFake(function(key) {
|
spyOn(locker, "get").and.callFake(function(key) {
|
||||||
return fakeStorage[key];
|
return fakeStorage[key];
|
||||||
});
|
});
|
||||||
spyOn(utils, "browserStorageCheck").and.returnValue(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("loadTrackPosition -", function() {
|
describe("loadTrackPosition -", function() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<li class="row song" ng-repeat="o in song" ng-click="selectSong(o)" ng-dblclick="playFrom($index)" ng-class="{'selected': o.selected, 'playing': o.playing}">
|
<li class="row song" ng-repeat="o in song" ng-click="selectSong(o)" ng-dblclick="playFrom($index)" ng-class="{'selected': o.selected, 'playing': o.playing}">
|
||||||
<div class="itemactions">
|
<div class="itemactions">
|
||||||
<!--<a class="add" href="" title="Add To Queue" ng-click="addSongToQueue(o)" stop-event="click"></a>-->
|
<a class="add" href="" title="Add To Queue" ng-click="addSongToQueue(o)" stop-event="click"></a>
|
||||||
<!--<a class="remove" href="" title="Remove Song" ng-click="removeSongFromQueue(o)" stop-event="click"></a>-->
|
<!--<a class="remove" href="" title="Remove Song" ng-click="removeSongFromQueue(o)" stop-event="click"></a>-->
|
||||||
<!--<a class="play" href="" title="Start Playing From This Song" ng-click="playFrom($index)" stop-event="click"></a>-->
|
<!--<a class="play" href="" title="Start Playing From This Song" ng-click="playFrom($index)" stop-event="click"></a>-->
|
||||||
<!--<a class="download" href="" title="Download Song" ng-click="download(o.id)"></a>-->
|
<!--<a class="download" href="" title="Download Song" ng-click="download(o.id)"></a>-->
|
||||||
|
|
|
@ -100,14 +100,6 @@ angular.module('jamstash.utils', ['jamstash.settings'])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// HTML5
|
|
||||||
this.browserStorageCheck = function () {
|
|
||||||
if (typeof (localStorage) === 'undefined') {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.timeToSeconds = function (time) {
|
this.timeToSeconds = function (time) {
|
||||||
var a = time.split(':'); // split it at the colons
|
var a = time.split(':'); // split it at the colons
|
||||||
var seconds;
|
var seconds;
|
||||||
|
|
|
@ -48,19 +48,7 @@
|
||||||
|
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div><!-- end #content -->
|
</div><!-- end #content -->
|
||||||
<div id="SideBar" ng-controller="QueueController">
|
<div id="SideBar" ng-include src="'queue/queue.html'" ng-controller="QueueController">
|
||||||
<div class="headeractions">
|
|
||||||
<a class="buttonimg" title="Shuffle Queue" ng-click="queueShuffle()"><img src="images/fork_gd_11x12.png"></a>
|
|
||||||
<a class="buttonimg" id="action_Empty" title="Delete Queue" ng-click="queueEmpty()"><img src="images/trash_fill_gd_12x12.png"></a>
|
|
||||||
<a class="buttonimg" id="action_DeleteSelected" title="Remove Selected From Queue" ng-click="queueRemoveSelected()"><img src="images/x_11x11.png"></a>
|
|
||||||
</div>
|
|
||||||
<div class="header">Queue</div>
|
|
||||||
<div id="SideQueue">
|
|
||||||
<ul class="simplelist songlist noselect">
|
|
||||||
<div ng-repeat="song in [player.queue] track by $index" class="songs" ng-include src="'common/songs_lite.html'" sortable></div>
|
|
||||||
</ul>
|
|
||||||
<div class="colspacer"></div>
|
|
||||||
</div>
|
|
||||||
<!--
|
<!--
|
||||||
<div id="NowPlaying">
|
<div id="NowPlaying">
|
||||||
<div class="header"><img src="images/rss_12x12.png" /> Now Playing</div>
|
<div class="header"><img src="images/rss_12x12.png" /> Now Playing</div>
|
||||||
|
|
|
@ -42,9 +42,11 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
|
||||||
currentTime: '#played',
|
currentTime: '#played',
|
||||||
duration: '#duration'
|
duration: '#duration'
|
||||||
},
|
},
|
||||||
|
setmedia: function() {
|
||||||
|
scope.scrobbled = false;
|
||||||
|
},
|
||||||
play: function() {
|
play: function() {
|
||||||
scope.revealControls();
|
scope.revealControls();
|
||||||
scope.scrobbled = false;
|
|
||||||
},
|
},
|
||||||
ended: function() {
|
ended: function() {
|
||||||
// We do this here and not on the service because we cannot create
|
// We do this here and not on the service because we cannot create
|
||||||
|
@ -60,7 +62,8 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
|
||||||
timeupdate: function (event) {
|
timeupdate: function (event) {
|
||||||
// Scrobble song once percentage is reached
|
// Scrobble song once percentage is reached
|
||||||
var p = event.jPlayer.status.currentPercentAbsolute;
|
var p = event.jPlayer.status.currentPercentAbsolute;
|
||||||
if (!scope.scrobbled && p > 30) {
|
var isPlaying = !event.jPlayer.status.paused;
|
||||||
|
if (!scope.scrobbled && p > 30 && isPlaying) {
|
||||||
if (globals.settings.Debug) { console.log('LAST.FM SCROBBLE - Percent Played: ' + p); }
|
if (globals.settings.Debug) { console.log('LAST.FM SCROBBLE - Percent Played: ' + p); }
|
||||||
subsonic.scrobble(scope.currentSong);
|
subsonic.scrobble(scope.currentSong);
|
||||||
scope.scrobbled = true;
|
scope.scrobbled = true;
|
||||||
|
@ -131,6 +134,7 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
|
||||||
.fadeTo("slow", 1).delay(500)
|
.fadeTo("slow", 1).delay(500)
|
||||||
.fadeTo("slow", 0).delay(500)
|
.fadeTo("slow", 0).delay(500)
|
||||||
.fadeTo("slow", 1);
|
.fadeTo("slow", 1);
|
||||||
|
//TODO: Hyz: Pass position and queue as parameter and move this away in another service
|
||||||
scope.saveTrackPosition();
|
scope.saveTrackPosition();
|
||||||
scope.saveQueue();
|
scope.saveQueue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,10 +134,10 @@ describe("jplayer directive", function() {
|
||||||
expect(scope.revealControls).toHaveBeenCalled();
|
expect(scope.revealControls).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("When jPlayer starts to play the current song, it resets the scrobbled flag to false", function() {
|
it("When jPlayer gets new media, it resets the scrobbled flag to false", function() {
|
||||||
scope.scrobbled = true;
|
scope.scrobbled = true;
|
||||||
|
|
||||||
var e = $.jPlayer.event.play;
|
var e = $.jPlayer.event.setmedia;
|
||||||
$player.trigger(e);
|
$player.trigger(e);
|
||||||
|
|
||||||
expect(scope.scrobbled).toBeFalsy();
|
expect(scope.scrobbled).toBeFalsy();
|
||||||
|
|
|
@ -80,19 +80,33 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
|
||||||
|
|
||||||
emptyQueue: function() {
|
emptyQueue: function() {
|
||||||
player.queue = [];
|
player.queue = [];
|
||||||
|
return player;
|
||||||
},
|
},
|
||||||
|
|
||||||
shuffleQueue: function() {
|
shuffleQueue: function() {
|
||||||
player.queue = _.shuffle(player.queue);
|
player.queue = _(player.queue).shuffle();
|
||||||
|
return player;
|
||||||
},
|
},
|
||||||
|
|
||||||
addSong: function(song) {
|
addSong: function(song) {
|
||||||
player.queue.push(song);
|
player.queue.push(song);
|
||||||
|
return player;
|
||||||
|
},
|
||||||
|
|
||||||
|
addSongs: function (songs) {
|
||||||
|
player.queue = player.queue.concat(songs);
|
||||||
|
return player;
|
||||||
},
|
},
|
||||||
|
|
||||||
removeSong: function(song) {
|
removeSong: function(song) {
|
||||||
var index = player.queue.indexOf(song);
|
var index = player.queue.indexOf(song);
|
||||||
player.queue.splice(index, 1);
|
player.queue.splice(index, 1);
|
||||||
|
return player;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSongs: function (songs) {
|
||||||
|
player.queue = _(player.queue).difference(songs);
|
||||||
|
return player;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPlayingSong: function() {
|
getPlayingSong: function() {
|
||||||
|
|
|
@ -139,11 +139,23 @@ describe("Player service -", function() {
|
||||||
expect(player.queue).toEqual([firstSong, secondSong, thirdSong, newSong]);
|
expect(player.queue).toEqual([firstSong, secondSong, thirdSong, newSong]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("when I add 3 songs to the queue, they are appended to the end of the playing queue", function() {
|
||||||
|
var secondNewSong = {id: 6338, name: 'Preconquest', artist: 'France Wisley', album: 'Unmix'};
|
||||||
|
var thirdNewSong = {id: 3696, name: 'Cetene', artist: 'Hilario Masley', album: 'Gonapophysal'};
|
||||||
|
player.addSongs([newSong, secondNewSong, thirdNewSong]);
|
||||||
|
expect(player.queue).toEqual([firstSong, secondSong, thirdSong, newSong, secondNewSong, thirdNewSong]);
|
||||||
|
});
|
||||||
|
|
||||||
it("when I remove the second song, the playing queue is now only the first and third song", function() {
|
it("when I remove the second song, the playing queue is now only the first and third song", function() {
|
||||||
player.removeSong(secondSong);
|
player.removeSong(secondSong);
|
||||||
expect(player.queue).toEqual([firstSong, thirdSong]);
|
expect(player.queue).toEqual([firstSong, thirdSong]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("when I remove the first and third songs, the playing queue is now only the second song", function() {
|
||||||
|
player.removeSongs([firstSong, thirdSong]);
|
||||||
|
expect(player.queue).toEqual([secondSong]);
|
||||||
|
});
|
||||||
|
|
||||||
it("when the first song is playing, isLastSongPlaying returns false", function() {
|
it("when the first song is playing, isLastSongPlaying returns false", function() {
|
||||||
player.playingIndex = 0;
|
player.playingIndex = 0;
|
||||||
expect(player.isLastSongPlaying()).toBeFalsy();
|
expect(player.isLastSongPlaying()).toBeFalsy();
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
<div id="queue" class="tabcontent">
|
<div class="headeractions">
|
||||||
<div class="section fullsection floatleft">
|
<a class="buttonimg" title="Shuffle Queue" ng-click="shuffleQueue()"><img src="images/fork_gd_11x12.png"></a>
|
||||||
<ul class="songlist simplelist noselect" ng-if="song.length > 0" ng-include src="'common/songs.html'" sortable></ul>
|
<a class="buttonimg" title="Delete Queue" ng-click="emptyQueue()"><img src="images/trash_fill_gd_12x12.png"></a>
|
||||||
|
<a class="buttonimg" title="Remove Selected From Queue" ng-click="removeSelectedSongsFromQueue()"><img src="images/x_11x11.png"></a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="header">Queue</div>
|
||||||
|
<div id="SideQueue">
|
||||||
|
<ul class="simplelist songlist noselect">
|
||||||
|
<div ng-repeat="song in [player.queue] track by $index" class="songs" sortable>
|
||||||
|
<li class="row song" ng-repeat="o in song" ng-click="selectSong(o)" ng-dblclick="playSong(o)" ng-class="{'selected': o.selected, 'playing': o.playing}">
|
||||||
|
<div class="itemactions">
|
||||||
|
<a class="remove" href="" title="Remove Song" ng-click="removeSongFromQueue(o)" stop-event="click"></a>
|
||||||
|
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
<div class="title floatleft" title="{{o.description}}" ng-bind-html="o.name"></div>
|
||||||
|
<div class="time floatleft">{{o.time}}</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
<div class="colspacer"></div>
|
||||||
</div>
|
</div>
|
|
@ -11,11 +11,13 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
|
||||||
player.play(song);
|
player.play(song);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.queueEmpty = function() {
|
$scope.emptyQueue = function() {
|
||||||
player.emptyQueue();
|
player.emptyQueue();
|
||||||
|
//TODO: Hyz: Shouldn't it be in a directive ?
|
||||||
|
$.fancybox.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.queueShuffle = function() {
|
$scope.shuffleQueue = function() {
|
||||||
player.shuffleQueue();
|
player.shuffleQueue();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,4 +28,8 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
|
||||||
$scope.removeSongFromQueue = function(song) {
|
$scope.removeSongFromQueue = function(song) {
|
||||||
player.removeSong(song);
|
player.removeSong(song);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.removeSelectedSongsFromQueue = function () {
|
||||||
|
player.removeSongs($scope.selectedSongs);
|
||||||
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -22,49 +22,41 @@ describe("Queue controller", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("When I call playSong, it calls play in the player service", function() {
|
it("When I play a song, it calls play in the player service", function() {
|
||||||
spyOn(player, "play");
|
spyOn(player, "play");
|
||||||
var songIndexInQueue = 3;
|
scope.playSong(song);
|
||||||
|
expect(player.play).toHaveBeenCalledWith(song);
|
||||||
scope.playSong(songIndexInQueue);
|
|
||||||
|
|
||||||
expect(player.play).toHaveBeenCalledWith(songIndexInQueue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("When I call queueEmpty, it calls emptyQueue in the player service", function() {
|
it("When I empty the queue, it calls emptyQueue in the player service", function() {
|
||||||
spyOn(player, "emptyQueue");
|
spyOn(player, "emptyQueue");
|
||||||
|
scope.emptyQueue();
|
||||||
scope.queueEmpty();
|
|
||||||
|
|
||||||
expect(player.emptyQueue).toHaveBeenCalled();
|
expect(player.emptyQueue).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("When I call queueShuffle, it calls shuffleQueue in the player service", function() {
|
it("When I shuffle the queue, it calls shuffleQueue in the player service", function() {
|
||||||
spyOn(player, "shuffleQueue");
|
spyOn(player, "shuffleQueue");
|
||||||
|
scope.shuffleQueue();
|
||||||
scope.queueShuffle();
|
|
||||||
|
|
||||||
expect(player.shuffleQueue).toHaveBeenCalled();
|
expect(player.shuffleQueue).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("When I add one song to the queue, it calls addSong in the player service", function() {
|
it("When I add one song to the queue, it calls addSong in the player service", function() {
|
||||||
spyOn(player, "addSong");
|
spyOn(player, "addSong");
|
||||||
|
|
||||||
|
|
||||||
scope.addSongToQueue(song);
|
scope.addSongToQueue(song);
|
||||||
|
|
||||||
expect(player.addSong).toHaveBeenCalledWith(song);
|
expect(player.addSong).toHaveBeenCalledWith(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
xit("When I add many songs to the queue, it calls addSong in the player service", function() {
|
|
||||||
spyOn(player, "addSong");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("When I remove a song from the queue, it calls removeSong in the player service", function() {
|
it("When I remove a song from the queue, it calls removeSong in the player service", function() {
|
||||||
spyOn(player, "removeSong");
|
spyOn(player, "removeSong");
|
||||||
|
|
||||||
scope.removeSongFromQueue(song);
|
scope.removeSongFromQueue(song);
|
||||||
|
|
||||||
expect(player.removeSong).toHaveBeenCalledWith(song);
|
expect(player.removeSong).toHaveBeenCalledWith(song);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("When I remove all the selected songs from the queue, it calls removeSongs in the player service", function() {
|
||||||
|
spyOn(player, "removeSongs");
|
||||||
|
var secondSong = { id: 6791 };
|
||||||
|
scope.selectedSongs = [song, secondSong];
|
||||||
|
scope.removeSelectedSongsFromQueue();
|
||||||
|
expect(player.removeSongs).toHaveBeenCalledWith([song, secondSong]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue