Refactor and docs

This commit is contained in:
An Phan 2015-12-23 01:46:54 +08:00
parent c071827fd5
commit 5e79a2737e
12 changed files with 96 additions and 116 deletions

View file

@ -24,11 +24,6 @@
import overlay from './components/shared/overlay.vue';
import sharedStore from './stores/shared';
import artistStore from './stores/artist';
import playlistStore from './stores/playlist';
import queueStore from './stores/queue';
import userStore from './stores/user';
import settingStore from './stores/setting';
import preferenceStore from './stores/preference';
import playback from './services/playback';
@ -56,7 +51,6 @@
// Make the most important HTTP request to get all necessary data from the server.
// Afterwards, init all mandatory stores and services.
sharedStore.init(() => {
this.initStores();
playback.init(this);
this.hideOverlay();
@ -70,21 +64,6 @@
},
methods: {
/**
* Initialize all stores to be used throughout the application.
*/
initStores() {
userStore.init();
preferenceStore.init();
// This will init album and song stores as well.
artistStore.init();
playlistStore.init();
queueStore.init();
settingStore.init();
},
/**
* Toggle playback when user presses Space key.
*

View file

@ -6,7 +6,6 @@ import songStore from './song';
export default {
stub,
artists: [],
state: {
albums: [stub],
@ -15,11 +14,9 @@ export default {
/**
* Init the store.
*
* @param array artists The array of artists to extract album data from.
* @param {Array} artists The array of artists to extract album data from.
*/
init(artists) {
this.artists = artists;
// Traverse through the artists array and add their albums into our master album list.
this.state.albums = _.reduce(artists, (albums, artist) => {
// While we're doing so, for each album, we get its length
@ -44,9 +41,9 @@ export default {
* Get the total length of an album by summing up its songs' duration.
* The length will also be converted into a H:i:s format and stored as fmtLength.
*
* @param object album
* @param {Array} album
*
* @return string The H:i:s format of the album.
* @return {String} The H:i:s format of the album length.
*/
getLength(album) {
album.length = _.reduce(album.songs, (length, song) => length + song.length, 0);

View file

@ -2,7 +2,6 @@ import _ from 'lodash';
import config from '../config';
import albumStore from './album';
import sharedStore from './shared';
export default {
state: {
@ -14,12 +13,8 @@ export default {
*
* @param {Array} artists The array of artists we got from the server.
*/
init(artists = null) {
this.state.artists = artists ? artists: sharedStore.state.artists;
// Init the album store. This must be called prior to the next logic,
// because we're using some data from the album store later.
albumStore.init(this.state.artists);
init(artists) {
this.state.artists = artists;
// Traverse through artists array to get the cover and number of songs for each.
_.each(this.state.artists, artist => {
@ -27,6 +22,8 @@ export default {
artist.songCount = _.reduce(artist.albums, (count, album) => count + album.songs.length, 0);
});
albumStore.init(this.state.artists);
},
all() {

View file

@ -16,8 +16,8 @@ export default {
* Toggle like/unlike a song.
* A request to the server will be made.
*
* @param object The song object
* @param closure|null The function to execute afterwards
* @param {Object} The song object
* @param {Function} The function to execute afterwards
*/
toggleOne(song, cb = null) {
http.post('interaction/like', { id: song.id }, data => {
@ -38,7 +38,7 @@ export default {
/**
* Add a song into the store.
*
* @param object The song object
* @param {Object} The song object
*/
add(song) {
this.state.songs.push(song);
@ -47,7 +47,7 @@ export default {
/**
* Remove a song from the store.
*
* @param object The song object
* @param {Object} The song object
*/
remove(song) {
this.state.songs = _.difference(this.state.songs, [song]);
@ -56,7 +56,7 @@ export default {
/**
* Like a bunch of songs.
*
* @param array An array of songs to like
* @param {Array} An array of songs to like
*/
like(songs, cb = null) {
this.state.songs = _.union(this.state.songs, songs);
@ -73,7 +73,7 @@ export default {
/**
* Unlike a bunch of songs.
*
* @param array An array of songs to unlike
* @param {Array} An array of songs to unlike
*/
unlike(songs, cb = null) {
this.state.songs = _.difference(this.state.songs, songs);

View file

@ -25,7 +25,7 @@ export default {
/**
* Get all songs in a playlist.
*
* return array
* return {Array}
*/
getSongs(playlist) {
return (playlist.songs = songStore.byIds(playlist.songs));

View file

@ -14,8 +14,9 @@ export default {
},
/**
* Init the store
* @param object user The user whose preferences we are managing.
* Init the store.
*
* @param {Object} user The user whose preferences we are managing.
*/
init(user = null) {
if (!user) {

View file

@ -51,9 +51,9 @@ export default {
* Add a list of songs to the end of the current queue,
* or replace the current queue as a whole if `replace` is true.
*
* @param object|array songs The song, or an array of songs
* @param bool replace Whether to replace the current queue
* @param bool toTop Whether to prepend of append to the queue
* @param {Object|Array} songs The song, or an array of songs
* @param {Boolean} replace Whether to replace the current queue
* @param {Boolean} toTop Whether to prepend of append to the queue
*/
queue(songs, replace = false, toTop = false) {
if (!Array.isArray(songs)) {
@ -74,7 +74,7 @@ export default {
/**
* Unqueue a song, or several songs at once.
*
* @param object|string|array songs The song(s) to unqueue.
* @param {Object|String|Array} songs The song(s) to unqueue.
*/
unqueue(songs) {
if (!Array.isArray(songs)) {
@ -98,7 +98,7 @@ export default {
/**
* Get the next song in queue.
*
* @return object|null
* @return {Object|Null}
*/
getNextSong() {
var i = _.pluck(this.state.songs, 'id').indexOf(this.current().id) + 1;
@ -109,7 +109,7 @@ export default {
/**
* Get the previous song in queue.
*
* @return object|null
* @return {Object|Null}
*/
getPrevSong() {
var i = _.pluck(this.state.songs, 'id').indexOf(this.current().id) - 1;

View file

@ -1,6 +1,14 @@
import http from '../services/http';
import { assign } from 'lodash';
import http from '../services/http';
import userStore from './user';
import preferenceStore from './preference';
import artistStore from './artist';
import songStore from './song';
import playlistStore from './playlist';
import queueStore from './queue';
import settingStore from './setting';
export default {
state: {
songs: [],
@ -17,7 +25,7 @@ export default {
},
init(cb = null) {
http.get('data', {}, data => {
http.get('data', data => {
assign(this.state, data);
// If this is a new user, initialize his preferences to be an empty object.
@ -25,6 +33,16 @@ export default {
this.state.currentUser.preferences = {};
}
userStore.init(this.state.users, this.state.currentUser);
preferenceStore.init(this.state.preferences);
artistStore.init(this.state.artists); // This will init album and song stores as well.
songStore.initInteractions(this.state.interactions);
playlistStore.init(this.state.playlists);
queueStore.init();
settingStore.init(this.state.settings);
window.useLastfm = this.state.useLastfm = data.useLastfm;
if (cb) {
cb();
}

View file

@ -3,32 +3,23 @@ import _ from 'lodash';
import http from '../services/http';
import utils from '../services/utils';
import stub from '../stubs/song';
import albumStore from './album';
import favoriteStore from './favorite';
import sharedStore from './shared';
import userStore from './user';
export default {
stub,
sharedStore: null,
albums: [],
state: {
songs: [stub],
interactions: [],
},
/**
* Init the store.
*
* @param array albums The array of albums to extract our songs from
* @param array interactions The array of interactions (like/play count) of the current user
* @param {Array} albums The array of albums to extract our songs from
*/
init(albums, interactions = null) {
this.albums = albums;
this.state.interactions = interactions ? interactions : sharedStore.state.interactions;
init(albums) {
// Iterate through the albums. With each, add its songs into our master song list.
this.state.songs = _.reduce(albums, (songs, album) => {
// While doing so, we populate some other information into the songs as well.
@ -37,20 +28,38 @@ export default {
// Keep a back reference to the album
song.album = album;
this.setInteractionStats(song);
if (song.liked) {
favoriteStore.add(song);
}
});
return songs.concat(album.songs);
}, []);
},
/**
* Initializes the interaction (like/play count) information.
*
* @param {Array} interactions The array of interactions of the current user
*/
initInteractions(interactions) {
_.each(interactions, interaction => {
var song = this.byId(interaction.song_id);
if (!song) {
return;
}
song.liked = interaction.liked;
song.playCount = interaction.play_count;
if (song.liked) {
favoriteStore.add(song);
}
});
},
/**
* Get all songs.
*
* @return {Array}
*/
all() {
return this.state.songs;
@ -59,9 +68,9 @@ export default {
/**
* Get a song by its ID
*
* @param string id
* @param {String} id
*
* @return object
* @return {Object}
*/
byId(id) {
return _.find(this.state.songs, {id});
@ -70,37 +79,18 @@ export default {
/**
* Get songs by their ID's
*
* @param array ids
* @param {Array} ids
*
* @return array
* @return {Array}
*/
byIds(ids) {
return _.filter(this.state.songs, song => _.contains(ids, song.id));
},
/**
* Set the interaction stats (like status and playcount) for a song.
*
* @param object song
*/
setInteractionStats(song) {
var interaction = _.find(this.state.interactions, { song_id: song.id });
if (!interaction) {
song.liked = false;
song.playCount = 0;
return;
}
song.liked = interaction.liked;
song.playCount = interaction.play_count;
},
/**
* Increase a play count for a song.
*
* @param object song
* @param {Object} song
*/
registerPlay(song) {
// Increase playcount
@ -159,7 +149,7 @@ export default {
* @param {Function} cb
*/
scrobble(song, cb = null) {
if (!sharedStore.state.useLastfm || !userStore.current().preferences.lastfm_session_key) {
if (!window.useLastfm || !userStore.current().preferences.lastfm_session_key) {
return;
}

View file

@ -15,19 +15,10 @@ export default {
/**
* Init the store.
*
* @param object data The data object that contain the users array.
* Mostly for DI and testing purpose.
* For production, this data is retrieved from the shared store.
*
*/
init(data = null) {
if (!data) {
data = sharedStore.state;
}
this.state.users = data.users;
this.state.current = data.currentUser;
init(users, currentUser) {
this.state.users = users;
this.state.current = currentUser;
// Set the avatar for each of the users…
_.each(this.state.users, this.setAvatar);
@ -36,6 +27,11 @@ export default {
this.setAvatar();
},
/**
* Get all users.
*
* @return {Array}
*/
all() {
return this.state.users;
},
@ -43,9 +39,9 @@ export default {
/**
* Get a user by his ID
*
* @param integer id
* @param {Integer} id
*
* @return object
* @return {Object}
*/
byId(id) {
return _.find(this.state.users, {id});
@ -65,7 +61,7 @@ export default {
/**
* Set a user's avatar using Gravatar's service.
*
* @param object user The user. If null, the current user.
* @param {Object} user The user. If null, the current user.
*/
setAvatar(user = null) {
if (!user) {
@ -78,7 +74,7 @@ export default {
/**
* Update the current user's profile.
*
* @param string password Can be an empty string if the user is not changing his password.
* @param {String} password Can be an empty string if the user is not changing his password.
*/
updateProfile(password = null, cb = null) {
http.put('me', {
@ -98,10 +94,10 @@ export default {
/**
* Stores a new user into the database.
*
* @param string name
* @param string email
* @param string password
* @param function cb
* @param {String} name
* @param {String} email
* @param {String} password
* @param {Function} cb
*/
store(name, email, password, cb = null) {
http.post('user', { name, email, password }, user => {

View file

@ -9,7 +9,7 @@ describe('stores/song', () => {
beforeEach(() => {
// This is ugly and not very "unit," but anyway.
albumStore.init(artists);
songStore.init(albumStore.all(), interactions);
songStore.init(albumStore.all());
});
describe('#init', () => {
@ -46,7 +46,9 @@ describe('stores/song', () => {
});
});
describe('#setInteractionStats', () => {
describe('#initInteractions', () => {
beforeEach(() => songStore.initInteractions(interactions));
it('correctly sets interaction status', () => {
let song = songStore.byId('cb7edeac1f097143e65b1b2cde102482');
song.liked.should.be.true;

View file

@ -4,7 +4,7 @@ import userStore from '../../stores/user';
import data from '../blobs/users';
describe('stores/user', () => {
beforeEach(() => userStore.init(data));
beforeEach(() => userStore.init(data.users, data.currentUser));
describe('#init', () => {
it('correctly sets data state', () => {