Added event handling and state change listeners.
This commit is contained in:
parent
0ad9dd9008
commit
b94622dddf
@ -13,6 +13,14 @@ export default class SongPlayer {
|
|||||||
this._playlist = playlist;
|
this._playlist = playlist;
|
||||||
this._current = 0;
|
this._current = 0;
|
||||||
this._volume = 1;
|
this._volume = 1;
|
||||||
|
this._playing = true;
|
||||||
|
|
||||||
|
this._playlistChangeListeners = [];
|
||||||
|
this._currentSongChangeListeners = [];
|
||||||
|
this._volumeChangeListeners = [];
|
||||||
|
this._playingChangeListener = [];
|
||||||
|
|
||||||
|
this._allAudioEventListeners = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,8 +29,12 @@ export default class SongPlayer {
|
|||||||
*/
|
*/
|
||||||
setPlaylist(playlist) {
|
setPlaylist(playlist) {
|
||||||
this._playlist.unloadAllAudio();
|
this._playlist.unloadAllAudio();
|
||||||
|
const old = this._playlist;
|
||||||
this._playlist = playlist;
|
this._playlist = playlist;
|
||||||
this._current = 0;
|
this._current = 0;
|
||||||
|
this._playlistChangeListeners.forEach(playlistChangeListener => {
|
||||||
|
playlistChangeListener(old, this.getPlaylist());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,10 +50,7 @@ export default class SongPlayer {
|
|||||||
* @returns {boolean} true if and only if successful in going to the next song.
|
* @returns {boolean} true if and only if successful in going to the next song.
|
||||||
*/
|
*/
|
||||||
next() {
|
next() {
|
||||||
if (this._current >= this._playlist.total() - 1) return false;
|
return this.changeCurrentSongIndex(this.getCurrentSongIndex() + 1);
|
||||||
this.getCurrentSong().unloadAudio();
|
|
||||||
this._current += 1;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,10 +59,7 @@ export default class SongPlayer {
|
|||||||
* @returns {boolean} true if and only if successful in going to the previous song.
|
* @returns {boolean} true if and only if successful in going to the previous song.
|
||||||
*/
|
*/
|
||||||
previous() {
|
previous() {
|
||||||
if (this._current <= 0) return false;
|
return this.changeCurrentSongIndex(this.getCurrentSongIndex() - 1);
|
||||||
this.getCurrentSong().unloadAudio();
|
|
||||||
this._current -= 1;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,24 +67,53 @@ export default class SongPlayer {
|
|||||||
* @param {number} index the index of the song to jump to.
|
* @param {number} index the index of the song to jump to.
|
||||||
* @returns {boolean} true if and only if successful jumping to the given index.
|
* @returns {boolean} true if and only if successful jumping to the given index.
|
||||||
*/
|
*/
|
||||||
changeCurrent(index) {
|
changeCurrentSongIndex(index) {
|
||||||
if (index >= this._playlist.total()) return false;
|
if (index >= this._playlist.total()) return false;
|
||||||
if (index <= 0) return false;
|
if (index <= 0) return false;
|
||||||
|
Object.keys(this._allAudioEventListeners).forEach(key => {
|
||||||
|
const listeners = this._allAudioEventListeners[key];
|
||||||
|
listeners.forEach(listener => {
|
||||||
|
this.getCurrentSong().getAudio().removeEventListener(key, listener);
|
||||||
|
});
|
||||||
|
});
|
||||||
this.getCurrentSong().unloadAudio();
|
this.getCurrentSong().unloadAudio();
|
||||||
|
const old = this.getCurrentSong();
|
||||||
this._current = index;
|
this._current = index;
|
||||||
|
this._currentSongChangeListeners.forEach(currentChangeListener => {
|
||||||
|
currentChangeListener(old, this.getCurrentSong());
|
||||||
|
});
|
||||||
|
Object.keys(this._allAudioEventListeners).forEach(key => {
|
||||||
|
const listeners = this._allAudioEventListeners[key];
|
||||||
|
listeners.forEach(listener => {
|
||||||
|
this.getCurrentSong().getAudio().addEventListener(key, listener);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (this._playing) {
|
||||||
|
this.playCurrent();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {number} the current song's index in the playlist.
|
||||||
|
*/
|
||||||
|
getCurrentSongIndex() {
|
||||||
|
return this._current;
|
||||||
|
}
|
||||||
|
|
||||||
playCurrent() {
|
playCurrent() {
|
||||||
this.getCurrentSong().getAudio((audio) => {
|
this.getCurrentSong().getAudio((audio) => {
|
||||||
// TODO: May need to perform synchronization check to see if this is still the song to be played.
|
// TODO: May need to perform synchronization check to see if this is still the song to be played.
|
||||||
audio.volume = this._volume;
|
audio.volume = this._volume;
|
||||||
audio.play();
|
audio.play();
|
||||||
});
|
});
|
||||||
|
this._playing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pauseCurrent() {
|
pauseCurrent() {
|
||||||
this.getCurrentSong().getAudio().pause();
|
this.getCurrentSong().getAudio().pause();
|
||||||
|
this._playing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,8 +153,16 @@ export default class SongPlayer {
|
|||||||
return this.getCurrentSong().getAudio().duration;
|
return this.getCurrentSong().getAudio().duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePlayElement() {
|
generatePlayElement(size = 64) {
|
||||||
// TODO: Generates a play button in html.
|
const playButton = document.createElement("button");
|
||||||
|
playButton.classList.add("player-ctrl");
|
||||||
|
playButton.classList.add("play");
|
||||||
|
playButton.style.width = size + "px";
|
||||||
|
playButton.style.height = size + "px";
|
||||||
|
playButton.style.borderLeftWidth = size + "px";
|
||||||
|
playButton.style.borderTopWidth = Math.floor(size / 2) + "px";
|
||||||
|
playButton.style.borderBottomWidth = Math.ceil(size / 2) + "px";
|
||||||
|
// TODO: Finish this play button with event listeners.
|
||||||
}
|
}
|
||||||
|
|
||||||
generateNextElement() {
|
generateNextElement() {
|
||||||
@ -141,4 +184,142 @@ export default class SongPlayer {
|
|||||||
getCurrentSong() {
|
getCurrentSong() {
|
||||||
return this._playlist.songAtIndex(this._current);
|
return this._playlist.songAtIndex(this._current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback changeListener
|
||||||
|
* @param {any} old the previous value.
|
||||||
|
* @param {any} current the the current (new) value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the listener to receive the updates.
|
||||||
|
* @returns {boolean} true if and only if successfully added the listener.
|
||||||
|
*/
|
||||||
|
addCurrentSongChangeListener(listener) {
|
||||||
|
if (this._currentSongChangeListeners.includes(listener)) return false;
|
||||||
|
this._currentChangeListener.push(listener);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the song change listener to remove.
|
||||||
|
* @returns {boolean} true if and only if the song change listener given was successfully removed.
|
||||||
|
*/
|
||||||
|
removeCurrentSongChangeListener(listener) {
|
||||||
|
const removeIndex = this._currentSongChangeListeners.indexOf(listener);
|
||||||
|
if (removeIndex < 0) return false;
|
||||||
|
|
||||||
|
this._currentSongChangeListeners.splice(removeIndex, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the playlist change listener to add to the callback list.
|
||||||
|
* @returns {boolean} true if and only if the given listener was successfully registered.
|
||||||
|
*/
|
||||||
|
addPlaylistChangeListener(listener) {
|
||||||
|
if (this._playlistChangeListeners.includes(listener)) return false;
|
||||||
|
this._playlistChangeListeners.push(listener);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the playlist change listener to remove.
|
||||||
|
* @returns {boolean} true if and only if a listener was successfully removed from the callback list.
|
||||||
|
*/
|
||||||
|
removePlaylistChangeListener(listener) {
|
||||||
|
const removeIndex = this._playlistChangeListeners.indexOf(listener);
|
||||||
|
if (removeIndex < 0) return false;
|
||||||
|
|
||||||
|
this.playlistChangeListener.splice(removeIndex, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the listener that is called when the player's volume is changed.
|
||||||
|
* @returns {boolean} true if and only if the listener was successfully added.
|
||||||
|
*/
|
||||||
|
addVolumeChangeListener(listener) {
|
||||||
|
if (this._volumeChangeListeners.includes(listener)) return false;
|
||||||
|
this._volumeChangeListeners.push(listener);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the volume change listener to remove.
|
||||||
|
* @returns {boolean} true if and only if a listener was successfully removed from the callback list.
|
||||||
|
*/
|
||||||
|
removeVolumeChangeListener(listener) {
|
||||||
|
const removeIndex = this._volumeChangeListeners.indexOf(listener);
|
||||||
|
if (removeIndex < 0) return false;
|
||||||
|
|
||||||
|
this._volumeChangeListeners.splice(removeIndex, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the listener that is called when the player's volume is changed.
|
||||||
|
* @returns {boolean} true if and only if the listener was successfully added.
|
||||||
|
*/
|
||||||
|
addPlayChangeListener(listener) {
|
||||||
|
if (this._playingChangeListener.includes(listener)) return false;
|
||||||
|
this._playingChangeListener.push(listener);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {changeListener} listener the play change listener to remove.
|
||||||
|
* @returns {boolean} true if and only if a listener was successfully removed from the callback list.
|
||||||
|
*/
|
||||||
|
removePlayChangeListener(listener) {
|
||||||
|
const removeIndex = this._playingChangeListener.indexOf(listener);
|
||||||
|
if (removeIndex < 0) return false;
|
||||||
|
|
||||||
|
this._playingChangeListener.splice(removeIndex, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} type the type of the listener on the {@link HTMLAudioElement}.
|
||||||
|
* @param {EventListener|EventListenerObject} eventListener the event listener.
|
||||||
|
* @returns {boolean} true if and only if successfully registered event listener.
|
||||||
|
*/
|
||||||
|
addEventListenerToCurrentAudio(type, eventListener) {
|
||||||
|
let typeListeners = this._allAudioEventListeners[type];
|
||||||
|
if (!typeListeners) {
|
||||||
|
typeListeners = [];
|
||||||
|
this._allAudioEventListeners[type] = typeListeners;
|
||||||
|
}
|
||||||
|
if (typeListeners.includes(eventListener)) return false;
|
||||||
|
typeListeners.push(eventListener);
|
||||||
|
this.getCurrentSong().getAudio().addEventListener(type, eventListener);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} type the type of the listener on the {@link HTMLAudioElement}.
|
||||||
|
* @param {EventListener|EventListenerObject} eventListener the event listener.
|
||||||
|
* @returns {boolean} true if and only if the event listener was successfully added.
|
||||||
|
*/
|
||||||
|
removeEventListenerFromCurrentAudio(type, eventListener) {
|
||||||
|
let typeListeners = this._allAudioEventListeners[type];
|
||||||
|
if (!typeListeners) return false;
|
||||||
|
const removeIndex = typeListeners.indexOf(eventListener);
|
||||||
|
if (removeIndex < 0) return false;
|
||||||
|
typeListeners.splice(removeIndex, 1);
|
||||||
|
this.getCurrentSong().getAudio().removeEventListener(type, eventListener);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user