From 608d4f98e205a733a79866d1ec92ccdd5692fe49 Mon Sep 17 00:00:00 2001 From: Hyzual Date: Sat, 22 Nov 2014 18:58:15 +0100 Subject: [PATCH 01/39] Extracts the player into its own files. Creates a player directive, controller and service. Moves the HTML from inside index.html to its own player.html file. Conflicts: app/index.html --- app/app.js | 4 +- app/index.html | 106 +++++++---------------- app/player/player-directive.js | 23 +++++ app/{common => player}/player-service.js | 10 +-- app/player/player.html | 47 ++++++++++ app/player/player.js | 12 +++ app/player/player_test.js | 3 + 7 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 app/player/player-directive.js rename app/{common => player}/player-service.js (99%) create mode 100644 app/player/player.html create mode 100644 app/player/player.js create mode 100644 app/player/player_test.js diff --git a/app/app.js b/app/app.js index 66085f1..4059452 100755 --- a/app/app.js +++ b/app/app.js @@ -1,7 +1,7 @@ /* Declare app level module */ angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', - 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl']) + 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl', 'jamstash.player']) .config(['$routeProvider',function($routeProvider) { 'use strict'; @@ -51,4 +51,4 @@ angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', } }; }]); -}]); \ No newline at end of file +}]); diff --git a/app/index.html b/app/index.html index c0f2e1e..5d0d233 100755 --- a/app/index.html +++ b/app/index.html @@ -49,79 +49,33 @@
- - -
-
-
-
- - - - -
-
-
-
    -
  • -
  • -
-
- - - - - - - -
-
-
-
- -
-
-
-
-
-
00:00/00:00
-
-
-
-
-
-
+ + +
+ - - - - + + + + + diff --git a/app/player/player-directive.js b/app/player/player-directive.js new file mode 100644 index 0000000..a0e3c89 --- /dev/null +++ b/app/player/player-directive.js @@ -0,0 +1,23 @@ +angular.module('jamstash.player.directive', []) + +.directive('jamstashPlayer', function(){ + 'use strict'; + // Runs during compile + return { + name: 'jamstash.player', + // priority: 1, + // terminal: true, + scope: true, // {} = isolate, true = child, false/undefined = no change + // controller: function($scope, $element, $attrs, $transclude) {}, + // require: 'ngModel', // Array = multiple requires, ? = optional, ^ = check parent elements + restrict: 'E', + // template: '', + templateUrl: 'player/player.html', + replace: true, + // transclude: true, + // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})), + link: function($scope, iElm, iAttrs, controller) { + + } + }; +}); diff --git a/app/common/player-service.js b/app/player/player-service.js similarity index 99% rename from app/common/player-service.js rename to app/player/player-service.js index c0db6d7..a1ff3b6 100644 --- a/app/common/player-service.js +++ b/app/player/player-service.js @@ -1,4 +1,4 @@ -angular.module('JamStash') +angular.module('jamstash.player.service', []) .service('player', ['$rootScope', '$window', 'utils', 'globals', 'model', 'notifications', function ($rootScope, $window, utils, globals, model, notifications) { @@ -182,7 +182,7 @@ angular.module('JamStash') $rootScope.playSong = function (loadonly, data) { if (globals.settings.Debug) { console.log('Play: ' + JSON.stringify(data, null, 2)); } angular.forEach($rootScope.queue, function(item, key) { - item.playing = false; + item.playing = false; }); data.playing = true; data.selected = false; @@ -207,13 +207,13 @@ angular.module('JamStash') $('#playermiddle').css('visibility', 'visible'); $('#songdetails').css('visibility', 'visible'); - if (globals.settings.Jukebox) { + if (globals.settings.Jukebox) { $rootScope.addToJukebox(id); $rootScope.loadjPlayer(player1, url, suffix, true, position); } else { $rootScope.loadjPlayer(player1, url, suffix, loadonly, position); } - + var spechtml = ''; var data = $(player1).data().jPlayer; for (var i = 0; i < data.solutions.length; i++) { @@ -231,7 +231,7 @@ angular.module('JamStash') } $('#SMStats').html(spechtml); scrobbled = false; - + if ($rootScope.queue.length > 0) { $('#queue').stop().scrollTo('#' + id, 400); } diff --git a/app/player/player.html b/app/player/player.html new file mode 100644 index 0000000..4f51a9b --- /dev/null +++ b/app/player/player.html @@ -0,0 +1,47 @@ +
+
+
+
+ + + + +
+
+
+
    +
  • +
  • +
+
+ + + + + + + +
+
+
+
+ +
+
+
+
+
+
00:00/00:00
+
+
+
+
+
+
+
+
diff --git a/app/player/player.js b/app/player/player.js new file mode 100644 index 0000000..3f58c08 --- /dev/null +++ b/app/player/player.js @@ -0,0 +1,12 @@ +/** +* jamstash.player Module +* +* Control the HTML5 player through jplayer.js +*/ +angular.module('jamstash.player', ['jamstash.player.service', 'jamstash.player.directive']) + +.controller('PlayerCtrl', ['$scope', function($scope){ + 'use strict'; + + +}]); diff --git a/app/player/player_test.js b/app/player/player_test.js new file mode 100644 index 0000000..ae2d477 --- /dev/null +++ b/app/player/player_test.js @@ -0,0 +1,3 @@ +describe("Player controller", function() { + 'use strict'; +}); \ No newline at end of file From 8fff3c85975c17bf0b1d7140e223d7687679ff3c Mon Sep 17 00:00:00 2001 From: Hyzual Date: Sat, 22 Nov 2014 19:16:19 +0100 Subject: [PATCH 02/39] Adds size attributes to all images in player. Renames images to correspond to their actual size --- ...ause_alt_24x32.png => pause_alt_24x24.png} | Bin ...{play_alt_24x32.png => play_alt_24x24.png} | Bin app/player/player-directive.js | 4 +-- app/player/player.html | 34 ++++++++++-------- 4 files changed, 20 insertions(+), 18 deletions(-) rename app/images/{pause_alt_24x32.png => pause_alt_24x24.png} (100%) rename app/images/{play_alt_24x32.png => play_alt_24x24.png} (100%) diff --git a/app/images/pause_alt_24x32.png b/app/images/pause_alt_24x24.png similarity index 100% rename from app/images/pause_alt_24x32.png rename to app/images/pause_alt_24x24.png diff --git a/app/images/play_alt_24x32.png b/app/images/play_alt_24x24.png similarity index 100% rename from app/images/play_alt_24x32.png rename to app/images/play_alt_24x24.png diff --git a/app/player/player-directive.js b/app/player/player-directive.js index a0e3c89..9df0070 100644 --- a/app/player/player-directive.js +++ b/app/player/player-directive.js @@ -16,8 +16,6 @@ angular.module('jamstash.player.directive', []) replace: true, // transclude: true, // compile: function(tElement, tAttrs, function transclude(function(scope, cloneLinkingFn){ return function linking(scope, elm, attrs){}})), - link: function($scope, iElm, iAttrs, controller) { - - } + // link: function($scope, iElm, iAttrs, controller) {} }; }); diff --git a/app/player/player.html b/app/player/player.html index 4f51a9b..761be23 100644 --- a/app/player/player.html +++ b/app/player/player.html @@ -1,27 +1,31 @@ -
+
- - - - + + + +
-
+
+ + + +
-
- - - - - - - -
+
+ + + + + + + +
From 1a01c4c23ca1160098a0d4ab443ba8e07318403a Mon Sep 17 00:00:00 2001 From: Hyzual Date: Sat, 22 Nov 2014 20:15:24 +0100 Subject: [PATCH 03/39] First green test : changing nextTrack so it is not in the rootScope. --- app/player/player-service.js | 9 ++++--- app/player/player-service_test.js | 41 +++++++++++++++++++++++++++++++ app/player/player.html | 22 +++++++++++------ app/player/player.js | 37 +++++++++++++++++++++++++++- 4 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 app/player/player-service_test.js diff --git a/app/player/player-service.js b/app/player/player-service.js index a1ff3b6..467f6ce 100644 --- a/app/player/player-service.js +++ b/app/player/player-service.js @@ -1,4 +1,5 @@ -angular.module('jamstash.player.service', []) +angular.module('jamstash.player.service', ['jamstash.utils', 'jamstash.settings', 'jamstash.model', + 'jamstash.notifications']) .service('player', ['$rootScope', '$window', 'utils', 'globals', 'model', 'notifications', function ($rootScope, $window, utils, globals, model, notifications) { @@ -20,7 +21,7 @@ angular.module('jamstash.player.service', []) } } }; - $rootScope.nextTrack = function () { + this.nextTrack = function () { var next = getNextSong(); if (next) { $rootScope.playSong(false, next); @@ -215,7 +216,7 @@ angular.module('jamstash.player.service', []) } var spechtml = ''; - var data = $(player1).data().jPlayer; + /*FIXME: var data = $(player1).data().jPlayer; for (var i = 0; i < data.solutions.length; i++) { var solution = data.solutions[i]; if (data[solution].used) { @@ -228,7 +229,7 @@ angular.module('jamstash.player.service', []) }); spechtml += " support"; } - } + }*/ $('#SMStats').html(spechtml); scrobbled = false; diff --git a/app/player/player-service_test.js b/app/player/player-service_test.js new file mode 100644 index 0000000..0327fd5 --- /dev/null +++ b/app/player/player-service_test.js @@ -0,0 +1,41 @@ +describe("Player service", function() { + 'use strict'; + + var player, $rootScope; + beforeEach(function() { + module('jamstash.player.service'); + + inject(function (_player_, _$rootScope_) { + player = _player_; + $rootScope = _$rootScope_; + }); + }); + + describe("nextTrack -", function() { + + it("Given that I have 3 songs in my playing queue and no song is playing, it plays the first song", function() { + $rootScope.queue = [ + { + id: 6726, + name: 'Guarauno', + artist: 'Carlyn Pollack', + album: 'Arenig' + }, { + id: 2452, + name: 'Michoacan', + artist: 'Lura Jeppsen', + album: 'dioptrical' + }, { + id: 574, + name: 'Celtidaceae', + artist: 'Willard Steury', + album: 'redux' + } + ]; + + player.nextTrack(); + + expect($rootScope.queue[0].playing).toBeTruthy(); + }); + }); +}); diff --git a/app/player/player.html b/app/player/player.html index 761be23..d72ff32 100644 --- a/app/player/player.html +++ b/app/player/player.html @@ -2,17 +2,25 @@
+ + +
  • diff --git a/app/player/player.js b/app/player/player.js index 3f58c08..07d3dcd 100644 --- a/app/player/player.js +++ b/app/player/player.js @@ -5,8 +5,43 @@ */ angular.module('jamstash.player', ['jamstash.player.service', 'jamstash.player.directive']) -.controller('PlayerCtrl', ['$scope', function($scope){ +.controller('PlayerCtrl', ['$scope', 'player', function($scope, player){ 'use strict'; + $scope.playingSong = { + id: '', + album: '', + name: '', + specs: '', + starred: '', + coverartfull: '', + coverartthumb: '' + }; + + $scope.previousTrack = function () { + + }; + + $scope.defaultPlay = function () { + + }; + + $scope.nextTrack = function () { + + }; + + $scope.updateFavorite = function (song) { + + }; + + $scope.toggleSetting = function (settingName) { + + }; + + $scope.settings = { + SaveTrackPosition: '', + Jukebox: '', + Repeat: '' + }; }]); From 74ac275ecea9ea26848d9a44e0bed906a4f8f15e Mon Sep 17 00:00:00 2001 From: Hyzual Date: Tue, 25 Nov 2014 17:38:53 +0100 Subject: [PATCH 04/39] Refactors the player service. The idea is that the service should ideally be used directly, so we know who depends on what and don't end up with cycles. To achieve this, we should not add functions to $rootScope but instead provide them from our service. Services can use them directly, and controllers have to create other functions in their own scope. This means that we have a player-controller that does not do much by itself but it enables us to avoid filling up the $rootScope. I have left the $rootScope additions at the end of player-service because it's going to take some time to refactor it, so in the meantime I want things to keep working. --- app/app.js | 108 +++++++++++++++--------------- app/player/player-service.js | 16 +++-- app/player/player-service_test.js | 55 +++++++++++++-- app/player/player.html | 2 +- app/player/player.js | 35 ++-------- app/player/player_test.js | 42 +++++++++++- 6 files changed, 164 insertions(+), 94 deletions(-) diff --git a/app/app.js b/app/app.js index 4059452..b3df69c 100755 --- a/app/app.js +++ b/app/app.js @@ -1,54 +1,54 @@ - -/* Declare app level module */ -angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', - 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl', 'jamstash.player']) - -.config(['$routeProvider',function($routeProvider) { - 'use strict'; - - $routeProvider - .when('/index', { redirectTo: '/library' }) - .when('/settings', { templateUrl: 'settings/settings.html', controller: 'SettingsCtrl' }) - .when('/queue', { templateUrl: 'queue/queue.html', controller: 'QueueCtrl' }) - .when('/library', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl' }) - .when('/library/:artistId', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl', reloadOnSearch: false }) - .when('/library/:artistId/:albumId', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl', reloadOnSearch: false }) - .when('/podcasts', { templateUrl: 'podcasts/podcasts.html', controller: 'PodcastCtrl' }) - .when('/archive', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) - .when('/archive/:artist', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) - .when('/archive/:artist/:album', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) - .otherwise({ redirectTo: '/index' }); -}]) - -.config(['$httpProvider',function($httpProvider) { - 'use strict'; - - $httpProvider.interceptors.push(['$rootScope', '$location', '$q', 'globals', function ($rootScope, $location, $q, globals) { - return { - 'request': function (request) { - // if we're not logged-in to the AngularJS app, redirect to login page - //$rootScope.loggedIn = $rootScope.loggedIn || globals.settings.Username; - $rootScope.loggedIn = false; - if (globals.settings.Username != "" && globals.settings.Password != "" && globals.settings.Server != "") { - $rootScope.loggedIn = true; - } - var path = ''; - path = $location.path(); - if (globals.settings.Debug) { console.log('Logged In: ' + $rootScope.loggedIn); } - if (globals.settings.Debug) { console.log('Current Path: ' + path); } - if (!$rootScope.loggedIn && path != '/settings' && path.search('archive') < 0) { - $location.path('/settings'); - } - return request; - }, - 'responseError': function (rejection) { - // if we're not logged-in to the web service, redirect to login page - if (rejection.status === 401 && $location.path() != '/settings') { - $rootScope.loggedIn = false; - $location.path('/settings'); - } - return $q.reject(rejection); - } - }; - }]); -}]); + +/* Declare app level module */ +angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', + 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl', 'jamstash.player.ctrl']) + +.config(['$routeProvider',function($routeProvider) { + 'use strict'; + + $routeProvider + .when('/index', { redirectTo: '/library' }) + .when('/settings', { templateUrl: 'settings/settings.html', controller: 'SettingsCtrl' }) + .when('/queue', { templateUrl: 'queue/queue.html', controller: 'QueueCtrl' }) + .when('/library', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl' }) + .when('/library/:artistId', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl', reloadOnSearch: false }) + .when('/library/:artistId/:albumId', { templateUrl: 'subsonic/subsonic.html', controller: 'SubsonicCtrl', reloadOnSearch: false }) + .when('/podcasts', { templateUrl: 'podcasts/podcasts.html', controller: 'PodcastCtrl' }) + .when('/archive', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) + .when('/archive/:artist', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) + .when('/archive/:artist/:album', { templateUrl: 'archive/archive.html', controller: 'ArchiveCtrl' }) + .otherwise({ redirectTo: '/index' }); +}]) + +.config(['$httpProvider',function($httpProvider) { + 'use strict'; + + $httpProvider.interceptors.push(['$rootScope', '$location', '$q', 'globals', function ($rootScope, $location, $q, globals) { + return { + 'request': function (request) { + // if we're not logged-in to the AngularJS app, redirect to login page + //$rootScope.loggedIn = $rootScope.loggedIn || globals.settings.Username; + $rootScope.loggedIn = false; + if (globals.settings.Username != "" && globals.settings.Password != "" && globals.settings.Server != "") { + $rootScope.loggedIn = true; + } + var path = ''; + path = $location.path(); + if (globals.settings.Debug) { console.log('Logged In: ' + $rootScope.loggedIn); } + if (globals.settings.Debug) { console.log('Current Path: ' + path); } + if (!$rootScope.loggedIn && path != '/settings' && path.search('archive') < 0) { + $location.path('/settings'); + } + return request; + }, + 'responseError': function (rejection) { + // if we're not logged-in to the web service, redirect to login page + if (rejection.status === 401 && $location.path() != '/settings') { + $rootScope.loggedIn = false; + $location.path('/settings'); + } + return $q.reject(rejection); + } + }; + }]); +}]); diff --git a/app/player/player-service.js b/app/player/player-service.js index 467f6ce..14d70cf 100644 --- a/app/player/player-service.js +++ b/app/player/player-service.js @@ -9,7 +9,7 @@ angular.module('jamstash.player.service', ['jamstash.utils', 'jamstash.settings' var player2 = '#playdeck_2'; var scrobbled = false; var timerid = 0; - $rootScope.defaultPlay = function (data, event) { + this.defaultPlay = function (data, event) { if (typeof $(player1).data("jPlayer") == 'undefined') { $rootScope.nextTrack(); } @@ -27,7 +27,7 @@ angular.module('jamstash.player.service', ['jamstash.utils', 'jamstash.settings' $rootScope.playSong(false, next); } }; - $rootScope.previousTrack = function () { + this.previousTrack = function () { var next = getNextSong(true); if (next) { $rootScope.playSong(false, next); @@ -176,11 +176,11 @@ angular.module('jamstash.player.service', ['jamstash.utils', 'jamstash.settings' if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser, ' + html.length + ' characters'); } } }; - $rootScope.restartSong = function (loadonly, data) { + this.restartSong = function (loadonly, data) { var audio = $(player1).data("jPlayer"); audio.play(0); }; - $rootScope.playSong = function (loadonly, data) { + this.playSong = function (loadonly, data) { if (globals.settings.Debug) { console.log('Play: ' + JSON.stringify(data, null, 2)); } angular.forEach($rootScope.queue, function(item, key) { item.playing = false; @@ -413,4 +413,12 @@ angular.module('jamstash.player.service', ['jamstash.utils', 'jamstash.settings' } }); }; + + // TODO: Hyz: Those are temporary. Remove them when no one else is calling them. + // The idea is to have them so while refactoring so we don't break anything + $rootScope.defaultPlay = this.defaultPlay; + $rootScope.nextTrack = this.nextTrack; + $rootScope.previousTrack = this.previousTrack; + $rootScope.restartSong = this.restartSong; + $rootScope.playSong = this.playSong; }]); diff --git a/app/player/player-service_test.js b/app/player/player-service_test.js index 0327fd5..0459ed8 100644 --- a/app/player/player-service_test.js +++ b/app/player/player-service_test.js @@ -11,9 +11,10 @@ describe("Player service", function() { }); }); - describe("nextTrack -", function() { + describe("Given that I have 3 songs in my playing queue", function() { - it("Given that I have 3 songs in my playing queue and no song is playing, it plays the first song", function() { + var stubPlaySong, stubRestartSong; + beforeEach(function() { $rootScope.queue = [ { id: 6726, @@ -32,10 +33,56 @@ describe("Player service", function() { album: 'redux' } ]; + stubPlaySong = spyOn($rootScope, "playSong").and.stub(); + stubRestartSong = spyOn($rootScope, "restartSong").and.stub(); + }); - player.nextTrack(); + describe("when I call nextTrack", function() { + it("and no song is playing, it plays the first song", function() { + player.nextTrack(); - expect($rootScope.queue[0].playing).toBeTruthy(); + expect(stubPlaySong).toHaveBeenCalled(); + }); + + it("and the first song is playing, it plays the second song", function() { + $rootScope.queue[0].playing = true; + + player.nextTrack(); + + expect(stubPlaySong).toHaveBeenCalled(); + }); + + it("and the last song is playing, it does nothing", function() { + $rootScope.queue[2].playing = true; + + player.nextTrack(); + + expect(stubPlaySong).not.toHaveBeenCalled(); + }); + }); + + describe("when I call previousTrack", function() { + it("and no song is playing, it plays the first song", function() { + player.previousTrack(); + + expect(stubRestartSong).toHaveBeenCalled(); + }); + + it("and the first song is playing, it restarts the first song", function() { + $rootScope.queue[0].playing = true; + + player.previousTrack(); + + expect(stubRestartSong).toHaveBeenCalled(); + }); + + it("and the last song is playing, it plays the seconde song", function() { + $rootScope.queue[2].playing = true; + + player.previousTrack(); + + expect(stubPlaySong).toHaveBeenCalled(); + }); }); }); }); diff --git a/app/player/player.html b/app/player/player.html index d72ff32..96e50aa 100644 --- a/app/player/player.html +++ b/app/player/player.html @@ -18,7 +18,7 @@
      diff --git a/app/player/player.js b/app/player/player.js index 07d3dcd..d6a59e3 100644 --- a/app/player/player.js +++ b/app/player/player.js @@ -3,45 +3,20 @@ * * Control the HTML5 player through jplayer.js */ -angular.module('jamstash.player', ['jamstash.player.service', 'jamstash.player.directive']) +angular.module('jamstash.player.ctrl', ['jamstash.player.service', 'jamstash.player.directive']) .controller('PlayerCtrl', ['$scope', 'player', function($scope, player){ 'use strict'; - $scope.playingSong = { - id: '', - album: '', - name: '', - specs: '', - starred: '', - coverartfull: '', - coverartthumb: '' - }; - $scope.previousTrack = function () { - - }; - - $scope.defaultPlay = function () { - + player.previousTrack(); }; $scope.nextTrack = function () { - + player.nextTrack(); }; - $scope.updateFavorite = function (song) { - + $scope.defaultPlay = function () { + player.defaultPlay(); }; - - $scope.toggleSetting = function (settingName) { - - }; - - $scope.settings = { - SaveTrackPosition: '', - Jukebox: '', - Repeat: '' - }; - }]); diff --git a/app/player/player_test.js b/app/player/player_test.js index ae2d477..6391ee5 100644 --- a/app/player/player_test.js +++ b/app/player/player_test.js @@ -1,3 +1,43 @@ describe("Player controller", function() { 'use strict'; -}); \ No newline at end of file + + var player, scope, deferred; + + beforeEach(function() { + module('jamstash.player.ctrl'); + + inject(function ($controller, $rootScope, _player_, $q) { + scope = $rootScope.$new(); + player = _player_; + + // Mock the functions of the services + deferred = $q.defer(); + spyOn(player, "nextTrack").and.stub(); + spyOn(player, "previousTrack").and.stub(); + spyOn(player, "defaultPlay").and.stub(); + + $controller('PlayerCtrl', { + $scope: scope, + player: player + }); + }); + }); + + it("When I call previousTrack, it calls previousTrack in the player service", function() { + scope.previousTrack(); + + expect(player.previousTrack).toHaveBeenCalled(); + }); + + it("When I call nextTrack, it calls nextTrack in the player service", function() { + scope.nextTrack(); + + expect(player.nextTrack).toHaveBeenCalled(); + }); + + it("When I call defaultPlay, it calls defaultPlay in the player service", function() { + scope.defaultPlay(); + + expect(player.defaultPlay).toHaveBeenCalled(); + }); +}); From e5846e30f9e7cc296ba07faf99c004a169f16a2e Mon Sep 17 00:00:00 2001 From: Hyzual Date: Sun, 30 Nov 2014 18:02:15 +0100 Subject: [PATCH 05/39] Removes the player functions from the rootScope. However, saving track's position is broken. Some are still there because of problems I don't know how to solve, e.g. circular dependency between notifications and player. Uses the queue controller for the sidebar queue. Moves loadTrackPosition to the main controller. --- app/app.js | 2 +- app/archive/archive-service.js | 11 +- app/common/main-controller.js | 47 ++++-- app/common/main-controller_test.js | 30 ++++ app/common/notification-service.js | 2 +- app/index.html | 2 +- app/player/player-service.js | 174 +++++++++---------- app/player/player-service_test.js | 17 +- app/player/player_test.js | 5 +- app/queue/queue.js | 10 +- app/queue/queue_test.js | 30 ++++ app/subsonic/subsonic-service.js | 24 +-- app/subsonic/subsonic.js | 13 +- app/subsonic/subsonic_test.js | 263 +++++++++++++++-------------- 14 files changed, 352 insertions(+), 278 deletions(-) create mode 100644 app/common/main-controller_test.js create mode 100644 app/queue/queue_test.js diff --git a/app/app.js b/app/app.js index b3df69c..c15390a 100755 --- a/app/app.js +++ b/app/app.js @@ -1,7 +1,7 @@ /* Declare app level module */ angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize', - 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl', 'jamstash.player.ctrl']) + 'jamstash.subsonic.ctrl', 'jamstash.archive.ctrl', 'jamstash.player.ctrl', 'jamstash.queue.ctrl']) .config(['$routeProvider',function($routeProvider) { 'use strict'; diff --git a/app/archive/archive-service.js b/app/archive/archive-service.js index 141359d..3447bc9 100644 --- a/app/archive/archive-service.js +++ b/app/archive/archive-service.js @@ -3,10 +3,11 @@ * * Access Archive.org */ -angular.module('jamstash.archive.service', ['jamstash.settings', 'jamstash.model', 'jamstash.notifications']) +angular.module('jamstash.archive.service', ['jamstash.settings', 'jamstash.model', 'jamstash.notifications', + 'jamstash.player.service']) -.factory('archive', ['$rootScope', '$http', '$q', '$sce', 'globals', 'model', 'utils', 'map', 'notifications', - function($rootScope, $http, $q, $sce, globals, model, utils, map, notifications) { +.factory('archive', ['$rootScope', '$http', '$q', '$sce', 'globals', 'model', 'utils', 'map', 'notifications', 'player', + function($rootScope, $http, $q, $sce, globals, model, utils, map, notifications, player) { 'use strict'; var index = { shortcuts: [], artists: [] }; @@ -192,7 +193,7 @@ angular.module('jamstash.archive.service', ['jamstash.settings', 'jamstash.model } }); var next = $rootScope.queue[0]; - $rootScope.playSong(false, next); + player.playSong(false, next); notifications.updateMessage(Object.keys(items).length + ' Song(s) Added to Queue', true); } else { content.album = []; @@ -213,4 +214,4 @@ angular.module('jamstash.archive.service', ['jamstash.settings', 'jamstash.model return deferred.promise; } }; -}]); \ No newline at end of file +}]); diff --git a/app/common/main-controller.js b/app/common/main-controller.js index 377db03..bf0f52d 100644 --- a/app/common/main-controller.js +++ b/app/common/main-controller.js @@ -10,7 +10,7 @@ $rootScope.MusicFolders = []; $rootScope.Genres = []; $rootScope.Messages = []; - + $rootScope.SelectedMusicFolder = ""; $rootScope.unity = null; $rootScope.loggedIn = function () { @@ -27,13 +27,6 @@ $rootScope.go = function (path) { $location.path(path); }; - /* - $scope.playSong = function (loadonly, data) { - $scope.$apply(function () { - $rootScope.playSong(loadonly, data); - }); - } - */ // Reads cookies and sets globals.settings values $scope.loadSettings = function () { @@ -226,9 +219,9 @@ $('#left-component').stop().scrollTo(el, 400); } } else if (unicode == 39 || unicode == 176) { // right arrow - $rootScope.nextTrack(); + player.nextTrack(); } else if (unicode == 37 || unicode == 177) { // back arrow - $rootScope.previousTrack(); + player.previousTrack(); } else if (unicode == 32 || unicode == 179 || unicode.toString() == '0179') { // spacebar player.playPauseSong(); return false; @@ -286,7 +279,7 @@ $rootScope.selectAll(songs); $rootScope.addSongsToQueue(); var next = $rootScope.queue[0]; - $rootScope.playSong(false, next); + player.playSong(false, next); }; $rootScope.playFrom = function (index, songs) { var from = songs.slice(index,songs.length); @@ -299,7 +292,7 @@ $rootScope.queue = []; $rootScope.addSongsToQueue(); var next = $rootScope.queue[0]; - $rootScope.playSong(false, next); + player.playSong(false, next); } }; $rootScope.addSongsToQueue = function () { @@ -417,6 +410,12 @@ } }); }; + // 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; var starred = item.starred; @@ -441,7 +440,27 @@ $scope.toTrusted = function (html) { return $sce.trustAsHtml(html); }; - + + function loadTrackPosition() { + if (utils.browserStorageCheck()) { + // Load Saved Song + var song = angular.fromJson(localStorage.getItem('CurrentSong')); + if (song) { + player.playSong(true, song); + // Load Saved Queue + var items = angular.fromJson(localStorage.getItem('CurrentQueue')); + if (items) { + $rootScope.queue = items; + if ($rootScope.queue.length > 0) { + notifications.updateMessage($rootScope.queue.length + ' Saved Song(s)', true); + } + if (globals.settings.Debug) { console.log('Play Queue Loaded From localStorage: ' + $rootScope.queue.length + ' song(s)'); } + } + } + } else { + if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); } + } + } /* Launch on Startup */ $scope.loadSettings(); @@ -454,7 +473,7 @@ if ($scope.loggedIn()) { //$scope.ping(); if (globals.settings.SaveTrackPosition) { - player.loadTrackPosition(); + loadTrackPosition(); player.startSaveTrackPosition(); } } diff --git a/app/common/main-controller_test.js b/app/common/main-controller_test.js new file mode 100644 index 0000000..045974b --- /dev/null +++ b/app/common/main-controller_test.js @@ -0,0 +1,30 @@ +describe("Main controller", function() { + 'use strict'; + + describe("updateFavorite -", function() { + + it("when starring a song, it notifies the user that the star was saved", function() { + + }); + + it("when starring an album, it notifies the user that the star was saved", function() { + + }); + + it("when starring an artist, it notifies the user that the star was saved", function() { + + }); + + it("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 + }); + + it("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 + }); + }); + + describe("toggleSetting -", function() { + + }); +}); diff --git a/app/common/notification-service.js b/app/common/notification-service.js index 45a53fe..5716892 100644 --- a/app/common/notification-service.js +++ b/app/common/notification-service.js @@ -64,4 +64,4 @@ angular.module('jamstash.notifications', []) notifications[notification].close(); } }; -}]); \ No newline at end of file +}]); diff --git a/app/index.html b/app/index.html index 5d0d233..5877093 100755 --- a/app/index.html +++ b/app/index.html @@ -49,7 +49,7 @@
    -