Enable removing genre auto-playlists from the list
- Added an svg "X" icon to enable removing auto-playlists - Notice that the background-color and color change are done too, and since it's SVG, it takes only one image and some CSS to do both. - Added a subsonic.css file. It is intended (long term) to have all subsonic view-related CSS styles. - persistence-service now manages the selected genre auto-playlists names instead of utils.getValue(). - Rewrote persistence-service.js to comply with https://github.com/johnpapa/angular-styleguide#style-y052 - Rewrote many test descriptions in persistence-service_test.js to follow these recommendations : http://gojko.net/2015/02/25/how-to-get-the-most-out-of-given-when-then/
This commit is contained in:
parent
d2bdb8eed9
commit
48da0ee7f0
9 changed files with 600 additions and 393 deletions
|
@ -6,8 +6,6 @@ angular.module('JamStash')
|
|||
$rootScope.settings = globals.settings;
|
||||
$rootScope.song = [];
|
||||
$rootScope.playingSong = null;
|
||||
$rootScope.MusicFolders = [];
|
||||
$rootScope.Genres = [];
|
||||
$rootScope.Messages = [];
|
||||
|
||||
$rootScope.unity = null;
|
||||
|
@ -56,7 +54,6 @@ angular.module('JamStash')
|
|||
}
|
||||
if (utils.getValue("SavedCollections")) { globals.SavedCollections = utils.getValue("SavedCollections").split(","); }
|
||||
if (utils.getValue("DefaultCollection")) { globals.DefaultCollection = utils.getValue("DefaultCollection"); }
|
||||
if (utils.getValue("SavedGenres")) { globals.SavedGenres = utils.getValue("SavedGenres").split(","); }
|
||||
if (globals.settings.Debug) { console.log('Loaded Settings: ' + JSON.stringify(globals.settings, null, 2)); }
|
||||
};
|
||||
$scope.toggleSetting = function (setting) {
|
||||
|
|
|
@ -1,141 +1,24 @@
|
|||
'use strict';
|
||||
/**
|
||||
* jamstash.persistence Module
|
||||
*
|
||||
* Provides load, save and delete operations for the current song and queue.
|
||||
* Data storage provided by HTML5 localStorage.
|
||||
*/
|
||||
angular.module('jamstash.persistence', ['ngLodash', 'angular-locker',
|
||||
'jamstash.settings.service', 'jamstash.player.service', 'jamstash.notifications', 'jamstash.utils'])
|
||||
angular.module('jamstash.persistence', [
|
||||
'ngLodash',
|
||||
'angular-locker',
|
||||
'jamstash.settings.service',
|
||||
'jamstash.player.service',
|
||||
'jamstash.notifications',
|
||||
'jamstash.utils'
|
||||
])
|
||||
|
||||
.config(['lockerProvider', function (lockerProvider) {
|
||||
lockerProvider.setDefaultDriver('local')
|
||||
.setDefaultNamespace(false)
|
||||
.setEventsEnabled(false);
|
||||
}])
|
||||
.config(['lockerProvider', lockerConfig])
|
||||
|
||||
.service('persistence', ['lodash', 'globals', 'player', 'notifications', 'locker', 'json', 'jamstashVersionChangesets', 'utils',
|
||||
function (_, globals, player, notifications, locker, json, jamstashVersionChangesets, utils) {
|
||||
/* Manage current track */
|
||||
this.loadTrackPosition = function () {
|
||||
// Load Saved Song
|
||||
var song = locker.get('CurrentSong');
|
||||
if (song) {
|
||||
player.load(song);
|
||||
}
|
||||
if (globals.settings.Debug) { console.log('Current Position Loaded from localStorage: ', song); }
|
||||
};
|
||||
|
||||
this.saveTrackPosition = function (song) {
|
||||
locker.put('CurrentSong', song);
|
||||
if (globals.settings.Debug) { console.log('Saving Current Position: ', song); }
|
||||
};
|
||||
|
||||
this.deleteTrackPosition = function () {
|
||||
locker.forget('CurrentSong');
|
||||
if (globals.settings.Debug) { console.log('Removing Current Position from localStorage'); }
|
||||
};
|
||||
|
||||
/* Manage playing queue */
|
||||
this.loadQueue = function () {
|
||||
// load Saved queue
|
||||
var queue = locker.get('CurrentQueue');
|
||||
if (queue) {
|
||||
player.addSongs(queue);
|
||||
if (player.queue.length > 0) {
|
||||
notifications.updateMessage(player.queue.length + ' Saved Song(s)', true);
|
||||
}
|
||||
if (globals.settings.Debug) { console.log('Play Queue Loaded from localStorage: ' + player.queue.length + ' song(s)'); }
|
||||
}
|
||||
};
|
||||
|
||||
this.saveQueue = function () {
|
||||
locker.put('CurrentQueue', player.queue);
|
||||
if (globals.settings.Debug) { console.log('Saving Queue: ' + player.queue.length + ' songs'); }
|
||||
};
|
||||
|
||||
this.deleteQueue = function () {
|
||||
locker.forget('CurrentQueue');
|
||||
if (globals.settings.Debug) { console.log('Removing Play Queue from localStorage'); }
|
||||
};
|
||||
|
||||
/* Manage player volume */
|
||||
this.getVolume = function () {
|
||||
var volume = locker.get('Volume');
|
||||
if (volume === undefined) {
|
||||
locker.put('Volume', 1.0);
|
||||
volume = 1.0;
|
||||
}
|
||||
return volume;
|
||||
};
|
||||
|
||||
this.saveVolume = function (volume) {
|
||||
locker.put('Volume', volume);
|
||||
};
|
||||
|
||||
this.deleteVolume = function () {
|
||||
locker.forget('Volume');
|
||||
};
|
||||
|
||||
/* Manage selected music folder */
|
||||
this.getSelectedMusicFolder = function () {
|
||||
return locker.get('MusicFolders');
|
||||
};
|
||||
|
||||
this.saveSelectedMusicFolder = function (selectedMusicFolder) {
|
||||
locker.put('MusicFolders', selectedMusicFolder);
|
||||
};
|
||||
|
||||
this.deleteSelectedMusicFolder = function () {
|
||||
locker.forget('MusicFolders');
|
||||
};
|
||||
|
||||
/* Manage user settings */
|
||||
this.getSettings = function () {
|
||||
// If the latest version from changelog.json is newer than the version stored in local storage,
|
||||
// we upgrade it
|
||||
var storedVersion = this.getVersion();
|
||||
var persistenceService = this;
|
||||
json.getChangeLog(function (changelogs) {
|
||||
var changelogVersion = changelogs[0].version;
|
||||
if(utils.checkVersionNewer(changelogVersion, storedVersion)) {
|
||||
persistenceService.upgradeVersion(storedVersion, changelogVersion);
|
||||
}
|
||||
});
|
||||
return locker.get('Settings');
|
||||
};
|
||||
|
||||
this.saveSettings = function (settings) {
|
||||
locker.put('Settings', settings);
|
||||
};
|
||||
|
||||
this.deleteSettings = function () {
|
||||
locker.forget('Settings');
|
||||
};
|
||||
|
||||
/* Manage Jamstash Version */
|
||||
this.getVersion = function () {
|
||||
return locker.get('JamstashVersion');
|
||||
};
|
||||
|
||||
this.upgradeVersion = function (currentVersion, finalVersion) {
|
||||
var settings = locker.get('Settings');
|
||||
// Apply all upgrades older than the final version and newer than the current
|
||||
var allUpgrades = _.filter(jamstashVersionChangesets.versions, function (toApply) {
|
||||
var olderOrEqualToFinal = utils.checkVersion(finalVersion, toApply.version);
|
||||
var newerThanCurrent = utils.checkVersionNewer(toApply.version, currentVersion);
|
||||
return olderOrEqualToFinal && newerThanCurrent;
|
||||
});
|
||||
_.forEach(allUpgrades, function (versionUpg) {
|
||||
versionUpg.changeset(settings);
|
||||
});
|
||||
this.saveSettings(settings);
|
||||
locker.put('JamstashVersion', finalVersion);
|
||||
notifications.updateMessage('Version ' + currentVersion + ' to ' + finalVersion, true);
|
||||
};
|
||||
}])
|
||||
.service('persistence', persistenceService)
|
||||
|
||||
.value('jamstashVersionChangesets', {
|
||||
// jshint strict: false
|
||||
versions: [
|
||||
{
|
||||
version: '4.4.5',
|
||||
|
@ -146,3 +29,187 @@ angular.module('jamstash.persistence', ['ngLodash', 'angular-locker',
|
|||
]
|
||||
});
|
||||
|
||||
lockerConfig.$inject = ['lockerProvider'];
|
||||
|
||||
function lockerConfig(lockerProvider) {
|
||||
'use strict';
|
||||
lockerProvider.setDefaultDriver('local')
|
||||
.setDefaultNamespace(false)
|
||||
.setEventsEnabled(false);
|
||||
}
|
||||
|
||||
persistenceService.$inject = [
|
||||
'lodash',
|
||||
'globals',
|
||||
'player',
|
||||
'notifications',
|
||||
'locker',
|
||||
'json',
|
||||
'jamstashVersionChangesets',
|
||||
'utils'
|
||||
];
|
||||
|
||||
function persistenceService(_, globals, player, notifications, locker, json, jamstashVersionChangesets, utils) {
|
||||
'use strict';
|
||||
|
||||
const CURRENT_SONG = 'CurrentSong',
|
||||
CURRENT_QUEUE = 'CurrentQueue',
|
||||
VOLUME = 'Volume',
|
||||
MUSIC_FOLDERS = 'MusicFolders',
|
||||
GENRES = 'SavedGenres',
|
||||
SETTINGS = 'Settings';
|
||||
|
||||
// jshint validthis: true
|
||||
var self = this;
|
||||
_.extend(self, {
|
||||
loadTrackPosition : loadTrackPosition,
|
||||
saveTrackPosition : saveTrackPosition,
|
||||
deleteTrackPosition : deleteTrackPosition,
|
||||
loadQueue : loadQueue,
|
||||
saveQueue : saveQueue,
|
||||
deleteQueue : deleteQueue,
|
||||
getVolume : getVolume,
|
||||
saveVolume : saveVolume,
|
||||
deleteVolume : deleteVolume,
|
||||
getSelectedMusicFolder : getSelectedMusicFolder,
|
||||
saveSelectedMusicFolder : saveSelectedMusicFolder,
|
||||
deleteSelectedMusicFolder: deleteSelectedMusicFolder,
|
||||
saveSelectedGenreNames : saveSelectedGenreNames,
|
||||
loadSelectedGenreNames : loadSelectedGenreNames,
|
||||
deleteSelectedGenreNames : deleteSelectedGenreNames,
|
||||
getSettings : getSettings,
|
||||
saveSettings : saveSettings,
|
||||
deleteSettings : deleteSettings,
|
||||
getVersion : getVersion,
|
||||
upgradeVersion : upgradeVersion
|
||||
});
|
||||
|
||||
return self;
|
||||
|
||||
function loadTrackPosition() {
|
||||
// Load Saved Song
|
||||
var song = locker.get(CURRENT_SONG);
|
||||
if (song) {
|
||||
player.load(song);
|
||||
}
|
||||
if (globals.settings.Debug) { console.log('Current Position Loaded from localStorage: ', song); }
|
||||
}
|
||||
|
||||
function saveTrackPosition(song) {
|
||||
locker.put(CURRENT_SONG, song);
|
||||
if (globals.settings.Debug) { console.log('Saving Current Position: ', song); }
|
||||
}
|
||||
|
||||
function deleteTrackPosition() {
|
||||
locker.forget(CURRENT_SONG);
|
||||
if (globals.settings.Debug) { console.log('Removing Current Position from localStorage'); }
|
||||
}
|
||||
|
||||
function loadQueue() {
|
||||
// load Saved queue
|
||||
var queue = locker.get(CURRENT_QUEUE);
|
||||
if (queue) {
|
||||
player.addSongs(queue);
|
||||
if (player.queue.length > 0) {
|
||||
notifications.updateMessage(player.queue.length + ' Saved Song(s)', true);
|
||||
}
|
||||
if (globals.settings.Debug) { console.log('Play Queue Loaded from localStorage: ' + player.queue.length + ' song(s)'); }
|
||||
}
|
||||
}
|
||||
|
||||
function saveQueue() {
|
||||
locker.put(CURRENT_QUEUE, player.queue);
|
||||
if (globals.settings.Debug) { console.log('Saving Queue: ' + player.queue.length + ' songs'); }
|
||||
}
|
||||
|
||||
function deleteQueue() {
|
||||
locker.forget(CURRENT_QUEUE);
|
||||
if (globals.settings.Debug) { console.log('Removing Play Queue from localStorage'); }
|
||||
}
|
||||
|
||||
function getVolume() {
|
||||
var volume = locker.get(VOLUME);
|
||||
if (volume === undefined) {
|
||||
locker.put(VOLUME, 1.0);
|
||||
volume = 1.0;
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
function saveVolume(volume) {
|
||||
locker.put(VOLUME, volume);
|
||||
}
|
||||
|
||||
function deleteVolume() {
|
||||
locker.forget(VOLUME);
|
||||
}
|
||||
|
||||
function getSelectedMusicFolder() {
|
||||
return locker.get(MUSIC_FOLDERS);
|
||||
}
|
||||
|
||||
function saveSelectedMusicFolder(selectedMusicFolder) {
|
||||
locker.put(MUSIC_FOLDERS, selectedMusicFolder);
|
||||
}
|
||||
|
||||
function deleteSelectedMusicFolder() {
|
||||
locker.forget(MUSIC_FOLDERS);
|
||||
}
|
||||
|
||||
function saveSelectedGenreNames(selectedGenreNames) {
|
||||
locker.put(GENRES, selectedGenreNames);
|
||||
}
|
||||
|
||||
function loadSelectedGenreNames() {
|
||||
var selectedGenreNames = locker.get(GENRES);
|
||||
if (selectedGenreNames === undefined) {
|
||||
selectedGenreNames = [];
|
||||
}
|
||||
return selectedGenreNames;
|
||||
}
|
||||
|
||||
function deleteSelectedGenreNames() {
|
||||
locker.forget(GENRES);
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
// If the latest version from changelog.json is newer than the version stored in local storage,
|
||||
// we upgrade it
|
||||
var storedVersion = self.getVersion();
|
||||
json.getChangeLog(function (changelogs) {
|
||||
var changelogVersion = changelogs[0].version;
|
||||
if (utils.checkVersionNewer(changelogVersion, storedVersion)) {
|
||||
self.upgradeVersion(storedVersion, changelogVersion);
|
||||
}
|
||||
});
|
||||
return locker.get(SETTINGS);
|
||||
}
|
||||
|
||||
function saveSettings(settings) {
|
||||
locker.put(SETTINGS, settings);
|
||||
}
|
||||
|
||||
function deleteSettings() {
|
||||
locker.forget(SETTINGS);
|
||||
}
|
||||
|
||||
function getVersion() {
|
||||
return locker.get('JamstashVersion');
|
||||
}
|
||||
|
||||
function upgradeVersion(currentVersion, finalVersion) {
|
||||
var settings = locker.get(SETTINGS);
|
||||
// Apply all upgrades older than the final version and newer than the current
|
||||
var allUpgrades = _.filter(jamstashVersionChangesets.versions, function (toApply) {
|
||||
var olderOrEqualToFinal = utils.checkVersion(finalVersion, toApply.version);
|
||||
var newerThanCurrent = utils.checkVersionNewer(toApply.version, currentVersion);
|
||||
return olderOrEqualToFinal && newerThanCurrent;
|
||||
});
|
||||
_.forEach(allUpgrades, function (versionUpg) {
|
||||
versionUpg.changeset(settings);
|
||||
});
|
||||
self.saveSettings(settings);
|
||||
locker.put('JamstashVersion', finalVersion);
|
||||
notifications.updateMessage('Version ' + currentVersion + ' to ' + finalVersion, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// jscs:disable validateQuoteMarks
|
||||
describe("Persistence service", function () {
|
||||
'use strict';
|
||||
|
||||
|
@ -53,7 +54,7 @@ describe("Persistence service", function() {
|
|||
|
||||
describe("loadTrackPosition() -", function () {
|
||||
it("Given a previously saved song in local storage, when I load the song, the player will load it", function () {
|
||||
fakeStorage = { 'CurrentSong': song };
|
||||
fakeStorage = { CurrentSong: song };
|
||||
|
||||
persistence.loadTrackPosition();
|
||||
|
||||
|
@ -68,12 +69,12 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("saveTrackPosition() - saves the current track's position in local storage", function() {
|
||||
it("saveTrackPosition() - Given a song object, when I save the current track's position, then it will be set in local storage", function () {
|
||||
persistence.saveTrackPosition(song);
|
||||
expect(locker.put).toHaveBeenCalledWith('CurrentSong', song);
|
||||
});
|
||||
|
||||
it("deleteTrackPosition() - deletes the current track from local storage", function() {
|
||||
it("deleteTrackPosition() - When I delete the current track, then it will be erased from local storage", function () {
|
||||
persistence.deleteTrackPosition();
|
||||
expect(locker.forget).toHaveBeenCalledWith('CurrentSong');
|
||||
});
|
||||
|
@ -92,7 +93,7 @@ describe("Persistence service", function() {
|
|||
{ id: 1617 },
|
||||
{ id: 9812 }
|
||||
];
|
||||
fakeStorage = { 'CurrentQueue': queue };
|
||||
fakeStorage = { CurrentQueue: queue };
|
||||
|
||||
persistence.loadQueue();
|
||||
|
||||
|
@ -110,7 +111,7 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("saveQueue() - saves the playing queue in local storage", function() {
|
||||
it("saveQueue() - Given an array of song objects, when I save the playing queue, then the array will be set in local storage", function () {
|
||||
player.queue = [
|
||||
{ id: 1245 },
|
||||
{ id: 7465 },
|
||||
|
@ -120,14 +121,14 @@ describe("Persistence service", function() {
|
|||
expect(locker.put).toHaveBeenCalledWith('CurrentQueue', player.queue);
|
||||
});
|
||||
|
||||
it("deleteQueue() - deletes the saved playing queue from local storage", function() {
|
||||
it("deleteQueue() - When I delete the playing queue, then it will be erased from local storage", function () {
|
||||
persistence.deleteQueue();
|
||||
expect(locker.forget).toHaveBeenCalledWith('CurrentQueue');
|
||||
});
|
||||
|
||||
describe("getVolume() -", function () {
|
||||
it("Given a previously saved volume value in local storage, it retrieves it", function () {
|
||||
fakeStorage = { 'Volume': 0.46582 };
|
||||
fakeStorage = { Volume: 0.46582 };
|
||||
|
||||
var volume = persistence.getVolume();
|
||||
|
||||
|
@ -144,12 +145,12 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("saveVolume() - given a volume, it will be saved in local storage", function() {
|
||||
it("saveVolume() - Given a volume, when I save the volume, then it will be set in local storage", function () {
|
||||
persistence.saveVolume(0.05167);
|
||||
expect(locker.put).toHaveBeenCalledWith('Volume', 0.05167);
|
||||
});
|
||||
|
||||
it("deleteVolume() - deletes the saved volume from local storage", function() {
|
||||
it("deleteVolume() - When I delete the volume, then it will be erased from local storage", function () {
|
||||
persistence.deleteVolume();
|
||||
expect(locker.forget).toHaveBeenCalledWith('Volume');
|
||||
});
|
||||
|
@ -157,9 +158,9 @@ describe("Persistence service", function() {
|
|||
describe("getSelectedMusicFolder() -", function () {
|
||||
it("Given a previously saved selected music folder in local storage, when I get the saved music folder, then an object containing the id and name of the selected music folder will be returned", function () {
|
||||
fakeStorage = {
|
||||
'MusicFolders': {
|
||||
'id': 74,
|
||||
'name': 'kooliman unhurled'
|
||||
MusicFolders: {
|
||||
id: 74,
|
||||
name: 'kooliman unhurled'
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -167,8 +168,8 @@ describe("Persistence service", function() {
|
|||
|
||||
expect(locker.get).toHaveBeenCalledWith('MusicFolders');
|
||||
expect(selectedMusicFolder).toEqual({
|
||||
'id': 74,
|
||||
'name': 'kooliman unhurled'
|
||||
id: 74,
|
||||
name: 'kooliman unhurled'
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -180,7 +181,7 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("saveSelectedMusicFolder() - given an object containing the id and name of the selected music folder, when I save the music folder, then it will be set in local storage", function() {
|
||||
it("saveSelectedMusicFolder() - Given an object containing the id and name of the selected music folder, when I save the music folder, then it will be set in local storage", function () {
|
||||
persistence.saveSelectedMusicFolder({
|
||||
id: 41,
|
||||
name: 'parlormaid carcinolytic'
|
||||
|
@ -191,11 +192,41 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("deleteSelectedMusicFolder() - when I delete the selected music folder, then it will be erased from local storage", function() {
|
||||
it("deleteSelectedMusicFolder() - When I delete the selected music folder, then it will be erased from local storage", function () {
|
||||
persistence.deleteSelectedMusicFolder();
|
||||
expect(locker.forget).toHaveBeenCalledWith('MusicFolders');
|
||||
});
|
||||
|
||||
describe("loadSelectedGenreNames() -", function () {
|
||||
it("Given a previously saved array of genre names in local storage, when I get the saved genre names, then an array of genre names will be returned", function () {
|
||||
fakeStorage = {
|
||||
SavedGenres: ['thermetrograph', 'balandra transrhodanian', 'loverdom codeposit']
|
||||
};
|
||||
|
||||
var selectedGenreNames = persistence.loadSelectedGenreNames();
|
||||
|
||||
expect(locker.get).toHaveBeenCalledWith('SavedGenres');
|
||||
expect(selectedGenreNames).toEqual(['thermetrograph', 'balandra transrhodanian', 'loverdom codeposit']);
|
||||
});
|
||||
|
||||
it("Given that no selected genre name was previously saved in local storage, when I get the saved genre names, then an empty array will be returned", function () {
|
||||
var selectedGenreNames = persistence.loadSelectedGenreNames();
|
||||
|
||||
expect(locker.get).toHaveBeenCalledWith('SavedGenres');
|
||||
expect(selectedGenreNames).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it("saveSelectedGenreNames() - Given an array of genre names, when I save the genre names, then the array will be set in local storage", function () {
|
||||
persistence.saveSelectedGenreNames(['verascope', 'diode encephalotome', 'already squabbly']);
|
||||
expect(locker.put).toHaveBeenCalledWith('SavedGenres', ['verascope', 'diode encephalotome', 'already squabbly']);
|
||||
});
|
||||
|
||||
it("deleteSelectedGenreNames() - When I delete the genre names, then they will be erased from local storage", function () {
|
||||
persistence.deleteSelectedGenreNames();
|
||||
expect(locker.forget).toHaveBeenCalledWith('SavedGenres');
|
||||
});
|
||||
|
||||
describe("getSettings() -", function () {
|
||||
beforeEach(function () {
|
||||
spyOn(persistence, 'upgradeVersion');
|
||||
|
@ -209,9 +240,9 @@ describe("Persistence service", function() {
|
|||
|
||||
it("Given previously saved user settings in local storage, a promise will be resovled with the user settings", function () {
|
||||
fakeStorage = {
|
||||
"Settings": {
|
||||
"url": "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||
"Username": "Haupert"
|
||||
Settings: {
|
||||
url: "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||
Username: "Haupert"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -219,8 +250,8 @@ describe("Persistence service", function() {
|
|||
|
||||
expect(locker.get).toHaveBeenCalledWith('Settings');
|
||||
expect(settings).toEqual({
|
||||
"url": "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||
"Username": "Haupert"
|
||||
url: "https://headed.com/aleurodidae/taistrel?a=roquet&b=trichophoric#cathole",
|
||||
Username: "Haupert"
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -240,25 +271,25 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("saveSettings() - given a user settings object, it will be saved in local storage", function() {
|
||||
it("saveSettings() - Given a user settings object, when I save the settings, then it will be set in local storage", function () {
|
||||
persistence.saveSettings({
|
||||
"url": "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||
"Username": "Herrig"
|
||||
url: "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||
Username: "Herrig"
|
||||
});
|
||||
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||
"url": "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||
"Username": "Herrig"
|
||||
url: "http://crotalic.com/cabernet/coelenteron?a=dayshine&b=pantaletless#sus",
|
||||
Username: "Herrig"
|
||||
});
|
||||
});
|
||||
|
||||
it("deleteSettings() - deletes the saved user settings from local storage", function() {
|
||||
it("deleteSettings() - When I delete the settings, then they will be erased from local storage", function () {
|
||||
persistence.deleteSettings();
|
||||
expect(locker.forget).toHaveBeenCalledWith('Settings');
|
||||
});
|
||||
|
||||
describe("getVersion() -", function () {
|
||||
it("Given a previously saved Jamstash version in local storage, it retrieves it", function() {
|
||||
fakeStorage = { 'JamstashVersion': '1.2.5' };
|
||||
it("Given a previously saved Jamstash version in local storage, when I get the version, then a string version number will be returned", function () {
|
||||
fakeStorage = { JamstashVersion: '1.2.5' };
|
||||
|
||||
var version = persistence.getVersion();
|
||||
|
||||
|
@ -266,7 +297,7 @@ describe("Persistence service", function() {
|
|||
expect(version).toBe('1.2.5');
|
||||
});
|
||||
|
||||
it("Given that no Jamstash version was previously saved in local storage, it returns undefined", function() {
|
||||
it("Given that no Jamstash version was previously saved in local storage, when I get the version, then undefined will be returned", function () {
|
||||
var version = persistence.getVersion();
|
||||
|
||||
expect(locker.get).toHaveBeenCalledWith('JamstashVersion');
|
||||
|
@ -316,7 +347,7 @@ describe("Persistence service", function() {
|
|||
};
|
||||
});
|
||||
|
||||
it("when I upgrade the storage version from '1.0.0' to '1.0.2', both changesets have been applied", function() {
|
||||
it("when I upgrade the storage version from '1.0.0' to '1.0.2', then both changesets will be applied", function () {
|
||||
persistence.upgradeVersion('1.0.0', '1.0.2');
|
||||
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||
DefaultSearchType: 0,
|
||||
|
@ -326,7 +357,7 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("when I upgrade the storage version from '1.0.0' to '1.0.1', only the '1.0.1' changeset has been applied", function() {
|
||||
it("when I upgrade the storage version from '1.0.0' to '1.0.1', only the '1.0.1' changeset will be applied", function () {
|
||||
persistence.upgradeVersion('1.0.0', '1.0.1');
|
||||
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||
DefaultSearchType: 0,
|
||||
|
@ -339,7 +370,7 @@ describe("Persistence service", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("when I upgrade the storage version from '1.0.1' to '1.0.2', only the '1.0.2' changeset has been applied", function() {
|
||||
it("when I upgrade the storage version from '1.0.1' to '1.0.2', only the '1.0.2' changeset will be applied", function () {
|
||||
persistence.upgradeVersion('1.0.1', '1.0.2');
|
||||
expect(locker.put).toHaveBeenCalledWith('Settings', {
|
||||
DefaultSearchType: {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<link href="" rel="stylesheet" type="text/css" data-name="theme" />
|
||||
<!-- build:css(app) styles/concat.min.css -->
|
||||
<link rel="stylesheet" href="player/player.css" />
|
||||
<link rel="stylesheet" href="subsonic/subsonic.css" />
|
||||
<link rel="stylesheet" href="player/repeat-directive/repeat-directive.css" />
|
||||
<link rel="stylesheet" href="subsonic/breadcrumbs-directive/breadcrumbs-directive.css" />
|
||||
<!-- endbuild -->
|
||||
|
|
|
@ -62,7 +62,6 @@ angular.module('jamstash.settings.service', [])
|
|||
ShowQueue: false
|
||||
};
|
||||
this.SavedCollections = [];
|
||||
this.SavedGenres = [];
|
||||
this.Player1 = '#playdeck_1';
|
||||
this.archiveUrl = 'https://archive.org/';
|
||||
this.ChangeLog = null;
|
||||
|
|
23
app/subsonic/subsonic.css
Normal file
23
app/subsonic/subsonic.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
.icon {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin: 3px auto;
|
||||
}
|
||||
|
||||
.list-item-remove {
|
||||
height: 18px;
|
||||
width: 20px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.list-item-remove:hover {
|
||||
background-color: #DEECFB;
|
||||
}
|
||||
|
||||
.list-item-remove:hover .icon-remove {
|
||||
fill: #4D4D4F;
|
||||
}
|
||||
|
||||
.icon-remove {
|
||||
fill: #adadad;
|
||||
}
|
|
@ -148,15 +148,51 @@
|
|||
<div class="title">Random</div>
|
||||
</li>
|
||||
<li class="index" id="auto">Genre Playlists</li>
|
||||
<select id="Genres" name="Genres" class="large" ng-model="selectedGenre" ng-options="o for o in Genres">
|
||||
<select
|
||||
id="Genres"
|
||||
name="Genres"
|
||||
class="large"
|
||||
ng-model="selectedGenre"
|
||||
ng-options="o for o in Genres"
|
||||
>
|
||||
<option value="">[Select Genre]</option>
|
||||
</select>
|
||||
<li class="item" ng-repeat="o in playlistsGenre" ng-click="getRandomSongs('display', o)" ng-class="{'selected': selectedAutoPlaylist == o}">
|
||||
<li
|
||||
class="item"
|
||||
ng-repeat="genrePlaylist in genrePlaylists track by $index"
|
||||
ng-click="getRandomSongs('display', genrePlaylist)"
|
||||
ng-class="{'selected': selectedAutoPlaylist === genrePlaylist}"
|
||||
>
|
||||
<div class="itemactions">
|
||||
<a class="add" href="" title="Add To Play Queue" ng-click="getRandomSongs('add', o)" stop-event="click"></a>
|
||||
<a class="play" href="" title="Play" ng-click="getRandomSongs('play', o)" stop-event="click"></a>
|
||||
<a
|
||||
class="add"
|
||||
href=""
|
||||
title="Add To Play Queue"
|
||||
ng-click="getRandomSongs('add', genrePlaylist)"
|
||||
stop-event="click"
|
||||
></a>
|
||||
<a
|
||||
class="play"
|
||||
href=""
|
||||
title="Play"
|
||||
ng-click="getRandomSongs('play', genrePlaylist)"
|
||||
stop-event="click"
|
||||
></a>
|
||||
</div>
|
||||
<span class="title">
|
||||
{{ genrePlaylist }}
|
||||
</span>
|
||||
<div
|
||||
title="Remove this auto-playlist"
|
||||
class="list-item-remove"
|
||||
ng-click="deleteGenrePlaylist(genrePlaylist)"
|
||||
stop-event="click"
|
||||
>
|
||||
<svg class="icon">
|
||||
<title>Remove this auto-playlist</title>
|
||||
<use xlink:href="images/sprite/iconic.svg#x" class="icon-remove"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="title">{{o}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="simplelist mainlist noselect">
|
||||
|
|
|
@ -210,18 +210,6 @@ angular.module('jamstash.subsonic.controller', [
|
|||
}
|
||||
});
|
||||
|
||||
$scope.searching = {
|
||||
query: '',
|
||||
typeId: globals.settings.DefaultSearchType,
|
||||
types: globals.SearchTypes
|
||||
};
|
||||
$scope.playlistsGenre = globals.SavedGenres;
|
||||
$scope.$watch('selectedGenre', function (newValue, oldValue) {
|
||||
if (newValue !== oldValue) {
|
||||
globals.SavedGenres.push(newValue);
|
||||
utils.setValue('SavedGenres', globals.SavedGenres.join(), false);
|
||||
}
|
||||
});
|
||||
$scope.rescanLibrary = function (data, event) {
|
||||
$.ajax({
|
||||
url: globals.BaseURL() + '/getUser.view?' + globals.BaseParams() + '&username=' + globals.settings.Username,
|
||||
|
@ -663,6 +651,28 @@ angular.module('jamstash.subsonic.controller', [
|
|||
});
|
||||
};
|
||||
|
||||
$scope.$watch('selectedGenre', function (newValue, oldValue) {
|
||||
if (newValue && newValue !== oldValue) {
|
||||
$scope.genrePlaylists = _($scope.genrePlaylists)
|
||||
.push(newValue)
|
||||
.uniq()
|
||||
.value();
|
||||
persistence.saveSelectedGenreNames($scope.genrePlaylists);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.loadGenrePlaylists = function () {
|
||||
$scope.genrePlaylists = persistence.loadSelectedGenreNames();
|
||||
};
|
||||
|
||||
$scope.deleteGenrePlaylist = function (genrePlaylist) {
|
||||
_.remove($scope.genrePlaylists, function (playlist) {
|
||||
return playlist === genrePlaylist;
|
||||
});
|
||||
persistence.deleteSelectedGenreNames();
|
||||
persistence.saveSelectedGenreNames($scope.genrePlaylists);
|
||||
};
|
||||
|
||||
$scope.getPodcasts = function () {
|
||||
var promise = subsonic.getPodcasts();
|
||||
$scope.handleErrors(promise).then(function (podcasts) {
|
||||
|
@ -722,10 +732,18 @@ angular.module('jamstash.subsonic.controller', [
|
|||
};
|
||||
|
||||
/* Launch on Startup */
|
||||
$scope.searching = {
|
||||
query: '',
|
||||
typeId: globals.settings.DefaultSearchType,
|
||||
types: globals.SearchTypes
|
||||
};
|
||||
$scope.genrePlaylists = [];
|
||||
$scope.MusicFolders = [];
|
||||
$scope.getMusicFolders();
|
||||
$scope.getArtists();
|
||||
$scope.getPlaylists();
|
||||
$scope.getGenres();
|
||||
$scope.loadGenrePlaylists();
|
||||
$scope.getPodcasts();
|
||||
$scope.openDefaultSection();
|
||||
if ($routeParams.artistId && $routeParams.albumId) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// jscs:disable validateQuoteMarks
|
||||
describe("Subsonic controller", function () {
|
||||
'use strict';
|
||||
|
||||
|
@ -24,7 +25,10 @@ describe("Subsonic controller", function() {
|
|||
persistence = jasmine.createSpyObj("persistence", [
|
||||
"getSelectedMusicFolder",
|
||||
"saveSelectedMusicFolder",
|
||||
"deleteSelectedMusicFolder"
|
||||
"deleteSelectedMusicFolder",
|
||||
"loadSelectedGenreNames",
|
||||
"saveSelectedGenreNames",
|
||||
"deleteSelectedGenreNames"
|
||||
]);
|
||||
breadcrumbs = jasmine.createSpyObj("breadcrumbs", [
|
||||
"reset",
|
||||
|
@ -228,7 +232,9 @@ describe("Subsonic controller", function() {
|
|||
var response;
|
||||
beforeEach(function () {
|
||||
response = [
|
||||
{id:"2548"}, {id:"8986"}, {id:"2986"}
|
||||
{ id: 2548 },
|
||||
{ id: 8986 },
|
||||
{ id: 2986 }
|
||||
];
|
||||
});
|
||||
|
||||
|
@ -373,7 +379,9 @@ describe("Subsonic controller", function() {
|
|||
scope.$apply();
|
||||
|
||||
expect(scope.song).toEqual([
|
||||
{id: "2548"}, {id: "8986"}, {id: "2986"}
|
||||
{ id: 2548 },
|
||||
{ id: 8986 },
|
||||
{ id: 2986 }
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -383,7 +391,9 @@ describe("Subsonic controller", function() {
|
|||
scope.$apply();
|
||||
|
||||
expect(player.addSongs).toHaveBeenCalledWith([
|
||||
{id: "2548"}, {id: "8986"}, {id: "2986"}
|
||||
{ id: 2548 },
|
||||
{ id: 8986 },
|
||||
{ id: 2986 }
|
||||
]);
|
||||
expect(notifications.updateMessage).toHaveBeenCalledWith('3 Song(s) Added to Queue', true);
|
||||
});
|
||||
|
@ -395,7 +405,9 @@ describe("Subsonic controller", function() {
|
|||
|
||||
expect(player.emptyQueue).toHaveBeenCalled();
|
||||
expect(player.addSongs).toHaveBeenCalledWith([
|
||||
{id: "2548"}, {id: "8986"}, {id: "2986"}
|
||||
{ id: 2548 },
|
||||
{ id: 8986 },
|
||||
{ id: 2986 }
|
||||
]);
|
||||
expect(player.playFirstSong).toHaveBeenCalled();
|
||||
expect(notifications.updateMessage).toHaveBeenCalledWith('3 Song(s) Added to Queue', true);
|
||||
|
@ -510,12 +522,12 @@ describe("Subsonic controller", function() {
|
|||
});
|
||||
|
||||
it("Given a song, when I call playSong, then the player service's queue will be emptied, the song will be added to the queue and played", function () {
|
||||
var fakeSong = {"id": 3572};
|
||||
var fakeSong = { id: 3572 };
|
||||
|
||||
scope.playSong(fakeSong);
|
||||
|
||||
expect(player.emptyQueue).toHaveBeenCalled();
|
||||
expect(player.addSong).toHaveBeenCalledWith({"id": 3572});
|
||||
expect(player.addSong).toHaveBeenCalledWith({ id: 3572 });
|
||||
expect(player.playFirstSong).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -628,7 +640,7 @@ describe("Subsonic controller", function() {
|
|||
|
||||
describe("and given that we had already queried the first 3 most played albums,", function () {
|
||||
beforeEach(function () {
|
||||
scope.autoAlbums['frequent'].offset = 3;
|
||||
scope.autoAlbums.frequent.offset = 3;
|
||||
});
|
||||
|
||||
it("when I get the next most played albums, then subsonic will be queried with an offset of 6", function () {
|
||||
|
@ -859,6 +871,46 @@ describe("Subsonic controller", function() {
|
|||
});
|
||||
});
|
||||
|
||||
it("Given a genre name, when I delete a genre playlist, then the list of genre playlists will be deleted from persistence and saved again without the given genre, and it will be removed from the list of genre playlists in the scope", function () {
|
||||
scope.genrePlaylists = ['Olivella gravitometer', 'Antonina', 'recondemnation interact'];
|
||||
|
||||
scope.deleteGenrePlaylist('Antonina');
|
||||
|
||||
expect(scope.genrePlaylists).toEqual(['Olivella gravitometer', 'recondemnation interact']);
|
||||
expect(persistence.deleteSelectedGenreNames).toHaveBeenCalled();
|
||||
expect(persistence.saveSelectedGenreNames).toHaveBeenCalledWith(['Olivella gravitometer', 'recondemnation interact']);
|
||||
});
|
||||
|
||||
describe("Given that the selected genre name changed,", function () {
|
||||
beforeEach(function () {
|
||||
scope.genrePlaylists = ['misanthropy skeipp', 'flourish'];
|
||||
});
|
||||
|
||||
it("then the new value will be added at the end of the genre playlists array and the array will be saved to persistence", function () {
|
||||
scope.selectedGenre = 'standstill gallivant';
|
||||
scope.$apply();
|
||||
|
||||
expect(scope.genrePlaylists).toEqual(['misanthropy skeipp', 'flourish', 'standstill gallivant']);
|
||||
expect(persistence.saveSelectedGenreNames).toHaveBeenCalledWith(['misanthropy skeipp', 'flourish', 'standstill gallivant']);
|
||||
});
|
||||
|
||||
it("and the new value is already in the genre playlists array, then the new value won't be duplicated in the array", function () {
|
||||
scope.selectedGenre = 'flourish';
|
||||
scope.$apply();
|
||||
|
||||
expect(scope.genrePlaylists).toEqual(['misanthropy skeipp', 'flourish']);
|
||||
});
|
||||
});
|
||||
|
||||
it("When I load the selected genre playlists, the genre playlists will be loaded from persistence and published on the scope ", function () {
|
||||
persistence.loadSelectedGenreNames.and.returnValue(['clabber diffidentness', 'perturbancy', 'unnavigable']);
|
||||
|
||||
scope.loadGenrePlaylists();
|
||||
|
||||
expect(scope.genrePlaylists).toEqual(['clabber diffidentness', 'perturbancy', 'unnavigable']);
|
||||
expect(persistence.loadSelectedGenreNames).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("getMusicFolders() -", function () {
|
||||
beforeEach(function () {
|
||||
subsonic.getMusicFolders.and.returnValue(deferred.promise);
|
||||
|
@ -946,7 +998,7 @@ describe("Subsonic controller", function() {
|
|||
deferred.resolve([
|
||||
{ id: 74, name: "Magdalen neolalia" },
|
||||
{ id: 2, name: "neolalia tribrac" },
|
||||
{id: 19, name: "neolaliaviator"},
|
||||
{ id: 19, name: "neolaliaviator" }
|
||||
]);
|
||||
scope.$apply();
|
||||
|
||||
|
@ -954,7 +1006,7 @@ describe("Subsonic controller", function() {
|
|||
expect(scope.album).toEqual([
|
||||
{ id: 74, name: "Magdalen neolalia" },
|
||||
{ id: 2, name: "neolalia tribrac" },
|
||||
{id: 19, name: "neolaliaviator"},
|
||||
{ id: 19, name: "neolaliaviator" }
|
||||
]);
|
||||
expect(scope.song).toEqual([]);
|
||||
expect(breadcrumbs.reset).toHaveBeenCalled();
|
||||
|
@ -965,7 +1017,7 @@ describe("Subsonic controller", function() {
|
|||
deferred.resolve([
|
||||
{ id: 645, name: "brazenly unsheriff" },
|
||||
{ id: 831, name: "planorotund brazenly" },
|
||||
{id: 181, name: "brazenlyon"},
|
||||
{ id: 181, name: "brazenlyon" }
|
||||
]);
|
||||
scope.$apply();
|
||||
|
||||
|
@ -973,7 +1025,7 @@ describe("Subsonic controller", function() {
|
|||
expect(scope.shortcut).toEqual([
|
||||
{ id: 645, name: "brazenly unsheriff" },
|
||||
{ id: 831, name: "planorotund brazenly" },
|
||||
{id: 181, name: "brazenlyon"},
|
||||
{ id: 181, name: "brazenlyon" }
|
||||
]);
|
||||
expect(scope.song).toEqual([]);
|
||||
expect(scope.album).toEqual([]);
|
||||
|
@ -996,21 +1048,4 @@ describe("Subsonic controller", function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("On startup,", function() {
|
||||
//TODO: Hyz: Search types and default types published at startup
|
||||
|
||||
xit("it loads the indexes, the playlists", function() {
|
||||
controllerParams.$scope.getArtists = jasmine.createSpy('getArtists');
|
||||
controllerParams.$scope.getPlaylists = jasmine.createSpy('getPlaylists');
|
||||
// spyOn(scope, 'getArtists');
|
||||
// spyOn(scope, 'getPlaylists');
|
||||
|
||||
$controller('SubsonicController', controllerParams);
|
||||
expect(scope.getArtists).toHaveBeenCalled();
|
||||
expect(scope.getPlaylists).toHaveBeenCalled();
|
||||
|
||||
//TODO: Hyz: Complete with everything called on startup
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue