Move starring songs to subsonic-service

So we keep all requests to subsonic in the same place and all use subsonicRequest()
This commit is contained in:
Hyzual 2015-05-14 13:39:59 +02:00
parent 832c410290
commit b96fe0ecf0
14 changed files with 108 additions and 66 deletions

View file

@ -44,7 +44,7 @@
<a class="add" href="" title="Add To Play Queue" ng-click="getSongs(o.id, 'add')" stop-event="click"></a>
<a class="play" href="" title="Play" ng-click="getSongs(o.id, 'play')" stop-event="click"></a>
<a class="download" href="" title="Download"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="toggleStar(o)" stop-event="click"></a>
</div>
<div class="albumart"><img ng-src="{{o.coverart}}" src="images/albumdefault_50.jpg"></div>
<div class="title">{{o.name}}</div>

View file

@ -166,6 +166,10 @@ angular.module('jamstash.archive.controller', ['jamstash.archive.service'])
$rootScope.removeSong(item, $scope.song);
};
$scope.toggleStar = function (item) {
//Do nothing: we aren't logged in archive.org, so we can't star anything there.
};
/* Launch on Startup */
//$scope.getArtists();
$scope.getAlbums();

View file

@ -1,6 +1,6 @@
angular.module('JamStash')
.controller('AppController', ['$scope', '$rootScope', '$document', '$window', '$location', '$cookieStore', '$http', 'utils', 'globals', 'model', 'notifications', 'player', 'persistence', 'Page',
function($scope, $rootScope, $document, $window, $location, $cookieStore, $http, utils, globals, model, notifications, player, persistence, Page) {
.controller('AppController', ['$scope', '$rootScope', '$document', '$window', '$location', '$cookieStore', '$http', 'utils', 'globals', 'model', 'notifications', 'player', 'persistence', 'Page', 'subsonic',
function ($scope, $rootScope, $document, $window, $location, $cookieStore, $http, utils, globals, model, notifications, player, persistence, Page, subsonic) {
'use strict';
$rootScope.settings = globals.settings;
@ -380,27 +380,13 @@ angular.module('JamStash')
});
};
$scope.updateFavorite = function (item) {
var id = item.id;
var starred = item.starred;
var url;
if (starred) {
url = globals.BaseURL() + '/unstar.view?' + globals.BaseParams() + '&id=' + id;
item.starred = undefined;
} else {
url = globals.BaseURL() + '/star.view?' + globals.BaseParams() + '&id=' + id;
item.starred = true;
}
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function () {
$scope.toggleStar = function (item) {
subsonic.toggleStar(item).then(function (newStarred) {
item.starred = newStarred;
notifications.updateMessage('Favorite Updated!', true);
}
});
};
$scope.toTrusted = function (html) {
return $sce.trustAsHtml(html);
};

View file

@ -1,13 +1,14 @@
describe("Main controller", function() {
'use strict';
var controllerParams, $controller, scope, mockGlobals, player, utils, persistence;
var controllerParams, $controller, $q, scope, mockGlobals, player, utils, persistence, subsonic, notifications,
deferred;
beforeEach(function() {
mockGlobals = {
settings: {
SaveTrackPosition: false,
ShowQueue: false,
Debug: true,
Debug: false,
Jukebox: false
}
};
@ -30,9 +31,21 @@ describe("Main controller", function() {
"saveSettings"
]);
inject(function (_$controller_, $rootScope, _$document_, _$window_, _$location_, _$cookieStore_, _utils_, globals, _model_, _notifications_, _Page_) {
// Mock the subsonic service
subsonic = jasmine.createSpyObj("subsonic", [
"toggleStar"
]);
// Mock the notifications service
notifications = jasmine.createSpyObj("notifications", [
"updateMessage"
]);
inject(function (_$controller_, $rootScope, _$q_, _$document_, _$window_, _$location_, _$cookieStore_, _utils_, globals, _model_, _Page_) {
scope = $rootScope.$new();
utils = _utils_;
$q = _$q_;
deferred = $q.defer();
spyOn(utils, "switchTheme");
@ -47,37 +60,15 @@ describe("Main controller", function() {
utils: utils,
globals: globals,
model: _model_,
notifications: _notifications_,
notifications: notifications,
player: player,
persistence: persistence,
Page: _Page_
Page: _Page_,
subsonic: subsonic
};
});
});
xdescribe("updateFavorite -", function() {
xit("when starring a song, it notifies the user that the star was saved", function() {
});
xit("when starring an album, it notifies the user that the star was saved", function() {
});
xit("when starring an artist, it notifies the user that the star was saved", function() {
});
xit("given that the Subsonic server returns an error, when starring something, it notifies the user with the error message", function() {
//TODO: move to higher level
});
xit("given that the Subsonic server is unreachable, when starring something, it notifies the user with the HTTP error code", function() {
//TODO: move to higher level
});
});
xdescribe("toggleSetting -", function() {
});
@ -191,6 +182,34 @@ describe("Main controller", function() {
});
});
describe("toggleStar() -", function() {
beforeEach(function() {
subsonic.toggleStar.and.returnValue(deferred.promise);
});
it("Given an artist that was not starred, when I toggle its star, then subsonic service will be called, the artist will be starred and a notification will be displayed", function() {
var artist = { id: 4218, starred: false };
scope.toggleStar(artist);
deferred.resolve(true);
scope.$apply();
expect(subsonic.toggleStar).toHaveBeenCalledWith(artist);
expect(artist.starred).toBeTruthy();
expect(notifications.updateMessage).toHaveBeenCalledWith('Favorite Updated!', true);
});
it("Given a song that was starred, when I toggle its star, then subsonic service will be called, the song will be starred and a notification will be displayed", function() {
var song = { id: 784, starred: true };
scope.toggleStar(song);
deferred.resolve(false);
scope.$apply();
expect(subsonic.toggleStar).toHaveBeenCalledWith(song);
expect(song.starred).toBeFalsy();
expect(notifications.updateMessage).toHaveBeenCalledWith('Favorite Updated!', true);
});
});
});
describe("When starting up,", function() {

View file

@ -4,7 +4,7 @@
<!--<a class="remove" href="" title="Remove Song" ng-click="removeSongFromQueue(o)" stop-event="click"></a>-->
<a class="play" href="" title="Play this song" ng-click="playSong(o)" stop-event="click"></a>
<!--<a class="download" href="" title="Download Song" ng-click="download(o.id)"></a>-->
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
<a href="" title="Star" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="toggleStar(o)" stop-event="click"></a>
<div class="clear"></div>
</div>
<div class="track floatleft" ng-bind-html="o.track"></div>

View file

@ -1,7 +1,7 @@
<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>
<a href="" title="Star" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="toggleStar(o)" stop-event="click"></a>
<div class="clear"></div>
</div>
<div class="title floatleft" title="{{o.description}}" ng-bind-html="o.name"></div>

View file

@ -29,7 +29,7 @@
<a href="" class="jukebox" title="Jukebox Mode [Beta]" ng-click="toggleSetting('Jukebox')" ng-class="{'hoverSelected': !settings.Jukebox }"></a>
<a href="" class="loop" title="Repeat" ng-click="toggleSetting('Repeat')" ng-class="{'hoverSelected': !settings.Repeat }"></a>
<a href="" id="action_SaveProgress" class="lock" title="Save Track Position: On" ng-show="settings.SaveTrackPosition"></a>
<a title="Favorite" href="" ng-class="{'favorite': getPlayingSong().starred, 'rate': !getPlayingSong().starred}" ng-click="updateFavorite(getPlayingSong())" stop-event="click"></a>
<a title="Favorite" href="" ng-class="{'favorite': getPlayingSong().starred, 'rate': !getPlayingSong().starred}" ng-click="toggleStar(getPlayingSong())" stop-event="click"></a>
<a href="" id="action_Mute" class="mute" title="Mute"></a>
<a href="" id="action_UnMute" class="unmute" title="Unmute" style="display: none;"></a>
<!--<div class="jp-volume-bar"><div class="jp-volume-bar-value"></div></div><a href="" id="action_VolumeMax" class="volume" title="Max Volume"></a>-->

View file

@ -8,7 +8,7 @@
angular.module('jamstash.player.controller', ['jamstash.player.service', 'jamstash.player.directive'])
.controller('PlayerController', ['$scope', 'player', 'globals',
function($scope, player, globals){
function ($scope, player, globals) {
'use strict';
$scope.getPlayingSong = player.getPlayingSong;
@ -31,6 +31,4 @@ angular.module('jamstash.player.controller', ['jamstash.player.service', 'jamsta
$scope.previousTrack = player.previousTrack;
$scope.nextTrack = player.nextTrack;
//TODO: Hyz: updateFavorite - leave in rootScope ?
}]);

View file

@ -35,6 +35,4 @@ describe("Player controller", function() {
expect(player.nextTrack).toHaveBeenCalled();
});
// TODO: updateFavorite
});

View file

@ -10,7 +10,7 @@
<li class="row song id{{o.id}}" ng-repeat="o in song" ng-click="selectSong(o)" ng-dblclick="playSong(o)" ng-class="{'selected': o.selected, 'playing': isPlayingSong(o)}">
<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>
<a href="" title="Star" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="toggleStar(o)" stop-event="click"></a>
<div class="clear"></div>
</div>
<div class="title floatleft" title="{{o.description}}" ng-bind-html="o.name"></div>

View file

@ -65,6 +65,4 @@ angular.module('jamstash.queue.controller', ['jamstash.player.service'])
end = ui.item.index();
player.queue.splice(end, 0, player.queue.splice(start, 1)[0]);
};
//TODO: Hyz: updateFavorite - leave in rootScope ?
}]);

View file

@ -5,10 +5,10 @@
* Also offers more fine-grained functionality that is not part of Subsonic's API.
*/
angular.module('jamstash.subsonic.service', ['angular-underscore/utils',
'jamstash.settings.service', 'jamstash.utils', 'jamstash.model', 'jamstash.notifications', 'jamstash.player.service'])
'jamstash.settings.service', 'jamstash.utils', 'jamstash.model'])
.factory('subsonic', ['$rootScope', '$http', '$q', 'globals', 'utils', 'map', 'notifications', 'player',
function ($rootScope, $http, $q, globals, utils, map, notifications, player) {
.factory('subsonic', ['$rootScope', '$http', '$q', 'globals', 'utils', 'map',
function ($rootScope, $http, $q, globals, utils, map) {
'use strict';
//TODO: Hyz: Remove when refactored
@ -587,6 +587,18 @@ angular.module('jamstash.subsonic.service', ['angular-underscore/utils',
return true;
});
return promise;
},
toggleStar: function (item) {
var partialUrl = (item.starred) ? 'unstar.view' : 'star.view';
var promise = subsonicService.subsonicRequest(partialUrl, {
params: {
id: item.id
}
}).then(function () {
return !item.starred;
});
return promise;
}
// End subsonic
};

View file

@ -570,6 +570,33 @@ describe("Subsonic service -", function() {
expect(promise).toBeResolvedWith(true);
});
describe("toggleStar() -", function() {
it("Given an item (can be an artist, an album or a song) that wasn't starred, when I toggle its star, then a promise will be resolved with true", function() {
var song = { id: 7748, starred: false };
var url = 'http://demo.subsonic.com/rest/star.view?' +
'c=Jamstash&callback=JSON_CALLBACK&f=jsonp'+'&id=7748'+'&p=enc:cGFzc3dvcmQ%3D&u=Hyzual&v=1.10.2';
mockBackend.expectJSONP(url).respond(JSON.stringify(response));
var promise = subsonic.toggleStar(song);
mockBackend.flush();
expect(promise).toBeResolvedWith(true);
});
it("Given an item (can be an artist, an album or a song) that was starred, when I toggle its star, then a promise will be resolved with false", function() {
var album = { id: 6631, starred: true };
var url = 'http://demo.subsonic.com/rest/unstar.view?' +
'c=Jamstash&callback=JSON_CALLBACK&f=jsonp'+'&id=6631'+'&p=enc:cGFzc3dvcmQ%3D&u=Hyzual&v=1.10.2';
mockBackend.expectJSONP(url).respond(JSON.stringify(response));
var promise = subsonic.toggleStar(album);
mockBackend.flush();
expect(promise).toBeResolvedWith(false);
});
});
describe("getArtists() -", function() {
beforeEach(function() {
url = 'http://demo.subsonic.com/rest/getIndexes.view?'+

View file

@ -54,7 +54,7 @@
<a class="add hover" href="" title="Add To Play Queue" ng-click="getSongs('add', o.id, o.name)" stop-event="click"></a>
<a class="play hover" href="" title="Play" ng-click="getSongs('play', o.id, o.name)" stop-event="click"></a>
<a class="download hover" href="" ng-click="download(o.id)" title="Download" stop-event="click"></a>
<a title="Favorite hover" href="" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
<a class="hover" href="" title="Star" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="toggleStar(o)" stop-event="click"></a>
<a class="info hover" href="" title="{{'Created: ' + o.date}}"></a>
</div>
<div class="albumart"><img ng-src="{{o.coverartthumb}}" src="images/albumdefault_160.jpg"></div>