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:
Hyzual 2015-01-03 14:07:22 +01:00
parent 83869b7808
commit c787c468b9
12 changed files with 85 additions and 89 deletions

View file

@ -304,18 +304,11 @@ angular.module('JamStash')
notifications.updateMessage($scope.selectedSongs.length + ' Song(s) Added to Queue', true);
$scope.selectedSongs.length = 0;
}
};
$scope.addSongToQueue = function (data) {
$rootScope.queue.push(data);
};
$rootScope.removeSong = function (item, songs) {
var index = songs.indexOf(item);
songs.splice(index, 1);
};
$scope.removeSongFromQueue = function (item) {
var index = $rootScope.queue.indexOf(item)
$rootScope.queue.splice(index, 1);
};
$scope.isActive = function (route) {
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 () {
var total = 0;
utils.arrayForEach(self.queue(), function (item) {
@ -369,10 +348,6 @@ angular.module('JamStash')
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.selectSong = function (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) {
var id = item.id;

View file

@ -66,7 +66,6 @@ describe("Main controller", function() {
spyOn(locker, "get").and.callFake(function(key) {
return fakeStorage[key];
});
spyOn(utils, "browserStorageCheck").and.returnValue(true);
});
describe("loadTrackPosition -", function() {

View file

@ -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}">
<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="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>-->

View file

@ -100,14 +100,6 @@ angular.module('jamstash.utils', ['jamstash.settings'])
break;
}
};
// HTML5
this.browserStorageCheck = function () {
if (typeof (localStorage) === 'undefined') {
return false;
} else {
return true;
}
};
this.timeToSeconds = function (time) {
var a = time.split(':'); // split it at the colons
var seconds;

View file

@ -48,19 +48,7 @@
<div class="clear"></div>
</div><!-- end #content -->
<div id="SideBar" 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="SideBar" ng-include src="'queue/queue.html'" ng-controller="QueueController">
<!--
<div id="NowPlaying">
<div class="header"><img src="images/rss_12x12.png" /> Now Playing</div>

View file

@ -42,9 +42,11 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
currentTime: '#played',
duration: '#duration'
},
setmedia: function() {
scope.scrobbled = false;
},
play: function() {
scope.revealControls();
scope.scrobbled = false;
},
ended: function() {
// 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) {
// Scrobble song once percentage is reached
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); }
subsonic.scrobble(scope.currentSong);
scope.scrobbled = true;
@ -131,6 +134,7 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
.fadeTo("slow", 1).delay(500)
.fadeTo("slow", 0).delay(500)
.fadeTo("slow", 1);
//TODO: Hyz: Pass position and queue as parameter and move this away in another service
scope.saveTrackPosition();
scope.saveQueue();
}

View file

@ -134,10 +134,10 @@ describe("jplayer directive", function() {
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;
var e = $.jPlayer.event.play;
var e = $.jPlayer.event.setmedia;
$player.trigger(e);
expect(scope.scrobbled).toBeFalsy();

View file

@ -80,19 +80,33 @@ angular.module('jamstash.player.service', ['jamstash.settings', 'angular-undersc
emptyQueue: function() {
player.queue = [];
return player;
},
shuffleQueue: function() {
player.queue = _.shuffle(player.queue);
player.queue = _(player.queue).shuffle();
return player;
},
addSong: function(song) {
player.queue.push(song);
return player;
},
addSongs: function (songs) {
player.queue = player.queue.concat(songs);
return player;
},
removeSong: function(song) {
var index = player.queue.indexOf(song);
player.queue.splice(index, 1);
return player;
},
removeSongs: function (songs) {
player.queue = _(player.queue).difference(songs);
return player;
},
getPlayingSong: function() {

View file

@ -139,11 +139,23 @@ describe("Player service -", function() {
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() {
player.removeSong(secondSong);
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() {
player.playingIndex = 0;
expect(player.isLastSongPlaying()).toBeFalsy();

View file

@ -1,5 +1,24 @@
<div id="queue" class="tabcontent">
<div class="section fullsection floatleft">
<ul class="songlist simplelist noselect" ng-if="song.length > 0" ng-include src="'common/songs.html'" sortable></ul>
</div>
<div class="headeractions">
<a class="buttonimg" title="Shuffle Queue" ng-click="shuffleQueue()"><img src="images/fork_gd_11x12.png"></a>
<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 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>

View file

@ -11,11 +11,13 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
player.play(song);
};
$scope.queueEmpty = function() {
$scope.emptyQueue = function() {
player.emptyQueue();
//TODO: Hyz: Shouldn't it be in a directive ?
$.fancybox.close();
};
$scope.queueShuffle = function() {
$scope.shuffleQueue = function() {
player.shuffleQueue();
};
@ -26,4 +28,8 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
$scope.removeSongFromQueue = function(song) {
player.removeSong(song);
};
$scope.removeSelectedSongsFromQueue = function () {
player.removeSongs($scope.selectedSongs);
};
}]);

View file

@ -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");
var songIndexInQueue = 3;
scope.playSong(songIndexInQueue);
expect(player.play).toHaveBeenCalledWith(songIndexInQueue);
scope.playSong(song);
expect(player.play).toHaveBeenCalledWith(song);
});
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");
scope.queueEmpty();
scope.emptyQueue();
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");
scope.queueShuffle();
scope.shuffleQueue();
expect(player.shuffleQueue).toHaveBeenCalled();
});
it("When I add one song to the queue, it calls addSong in the player service", function() {
spyOn(player, "addSong");
scope.addSongToQueue(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() {
spyOn(player, "removeSong");
scope.removeSongFromQueue(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]);
});
});