Basic playlist support for webplayer
Webplayer can now handle a basic playlist, pushing multiple songs in the playlist and passing from one song to another. Some things that are not yet working: * Using previous and next buttons and going outside of the playlist breaks things. * Random / repeat modes are not yet implemented. * Playlist is not exposed in the UI at the moment. * Seeking in a song is not exposed in the UI. * When playing a song, webplayer does not automatically play the next one when reaching the end of the song.
This commit is contained in:
parent
b7f2f32e1d
commit
ab7470d618
@ -127,11 +127,12 @@ export const PUSH_SONG = "PUSH_SONG";
|
||||
*
|
||||
* @param songID The id of the song to push.
|
||||
* @param index [Optional] The position to insert at in the playlist.
|
||||
* If negative, counts from the end. Defaults to last.
|
||||
* If negative, counts from the end. Undefined (default)
|
||||
* is last position.
|
||||
*
|
||||
* @return Dispatch a PUSH_SONG action.
|
||||
*/
|
||||
export function pushSong(songID, index=-1) {
|
||||
export function pushSong(songID, index) {
|
||||
return (dispatch) => {
|
||||
// Handle reference counting
|
||||
dispatch(incrementRefCount({
|
||||
@ -197,31 +198,31 @@ export function jumpToSong(songID) {
|
||||
}
|
||||
|
||||
|
||||
export const PLAY_PREVIOUS = "PLAY_PREVIOUS";
|
||||
export const PLAY_PREVIOUS_SONG = "PLAY_PREVIOUS_SONG";
|
||||
/**
|
||||
* Move one song backwards in the playlist.
|
||||
*
|
||||
* @return Dispatch a PLAY_PREVIOUS action.
|
||||
* @return Dispatch a PLAY_PREVIOUS_SONG action.
|
||||
*/
|
||||
export function playPrevious() {
|
||||
export function playPreviousSong() {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: PLAY_PREVIOUS,
|
||||
type: PLAY_PREVIOUS_SONG,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export const PLAY_NEXT = "PLAY_NEXT";
|
||||
export const PLAY_NEXT_SONG = "PLAY_NEXT_SONG";
|
||||
/**
|
||||
* Move one song forward in the playlist.
|
||||
*
|
||||
* @return Dispatch a PLAY_NEXT action.
|
||||
* @return Dispatch a PLAY_NEXT_SONG action.
|
||||
*/
|
||||
export function playNext() {
|
||||
export function playNextSong() {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: PLAY_NEXT,
|
||||
type: PLAY_NEXT_SONG,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -22,17 +22,47 @@ const albumMessages = defineMessages(messagesMap(Array.concat([], commonMessages
|
||||
* Track row in an album tracks table.
|
||||
*/
|
||||
class AlbumTrackRowCSSIntl extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Bind this
|
||||
this.onPlayClick = this.onPlayClick.bind(this);
|
||||
this.onPlayNextClick = this.onPlayNextClick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click on play button.
|
||||
*/
|
||||
onPlayClick() {
|
||||
$(this.refs.play).blur();
|
||||
this.props.playAction(this.props.song.get("id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click on play next button.
|
||||
*/
|
||||
onPlayNextClick() {
|
||||
$(this.refs.playNext).blur();
|
||||
this.props.playNextAction(this.props.song.get("id"));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { formatMessage } = this.props.intl;
|
||||
const length = formatLength(this.props.track.get("time"));
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<button styleName="play" title={formatMessage(albumMessages["app.common.play"])} onClick={() => this.props.playAction(this.props.track.get("id"))}>
|
||||
<button styleName="play" title={formatMessage(albumMessages["app.common.play"])} onClick={this.onPlayClick}>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...albumMessages["app.common.play"]} />
|
||||
</span>
|
||||
<FontAwesome name="play-circle-o" aria-hidden="true" />
|
||||
</button>
|
||||
<button styleName="playNext" title={formatMessage(albumMessages["app.common.playNext"])} onClick={this.onPlayNextClick} ref="playNext">
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...albumMessages["app.common.playNext"]} />
|
||||
</span>
|
||||
<FontAwesome name="plus-circle" aria-hidden="true" />
|
||||
</button>
|
||||
</td>
|
||||
<td>{this.props.track.get("track")}</td>
|
||||
@ -44,6 +74,7 @@ class AlbumTrackRowCSSIntl extends Component {
|
||||
}
|
||||
AlbumTrackRowCSSIntl.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
track: PropTypes.instanceOf(Immutable.Map).isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
@ -57,9 +88,9 @@ class AlbumTracksTableCSS extends Component {
|
||||
render() {
|
||||
let rows = [];
|
||||
// Build rows for each track
|
||||
const playAction = this.props.playAction;
|
||||
const { playAction, playNextAction } = this.props;
|
||||
this.props.tracks.forEach(function (item) {
|
||||
rows.push(<AlbumTrackRow playAction={playAction} track={item} key={item.get("id")} />);
|
||||
rows.push(<AlbumTrackRow playAction={playAction} playNextAction={playNextAction} track={item} key={item.get("id")} />);
|
||||
});
|
||||
return (
|
||||
<table className="table table-hover" styleName="songs">
|
||||
@ -72,6 +103,7 @@ class AlbumTracksTableCSS extends Component {
|
||||
}
|
||||
AlbumTracksTableCSS.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
tracks: PropTypes.instanceOf(Immutable.List).isRequired,
|
||||
};
|
||||
export let AlbumTracksTable = CSSModules(AlbumTracksTableCSS, css);
|
||||
@ -93,7 +125,7 @@ class AlbumRowCSS extends Component {
|
||||
<div className="col-xs-9 col-sm-10 table-responsive">
|
||||
{
|
||||
this.props.songs.size > 0 ?
|
||||
<AlbumTracksTable playAction={this.props.playAction} tracks={this.props.songs} /> :
|
||||
<AlbumTracksTable playAction={this.props.playAction} playNextAction={this.props.playNextAction} tracks={this.props.songs} /> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
@ -103,6 +135,7 @@ class AlbumRowCSS extends Component {
|
||||
}
|
||||
AlbumRowCSS.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
album: PropTypes.instanceOf(Immutable.Map).isRequired,
|
||||
songs: PropTypes.instanceOf(Immutable.List).isRequired,
|
||||
};
|
||||
|
@ -48,13 +48,13 @@ class ArtistCSS extends Component {
|
||||
|
||||
// Build album rows
|
||||
let albumsRows = [];
|
||||
const { albums, songs, playAction } = this.props;
|
||||
const { albums, songs, playAction, playNextAction } = this.props;
|
||||
if (albums && songs) {
|
||||
albums.forEach(function (album) {
|
||||
const albumSongs = album.get("tracks").map(
|
||||
id => songs.get(id)
|
||||
);
|
||||
albumsRows.push(<AlbumRow playAction={playAction} album={album} songs={albumSongs} key={album.get("id")} />);
|
||||
albumsRows.push(<AlbumRow playAction={playAction} playNextAction={playNextAction} album={album} songs={albumSongs} key={album.get("id")} />);
|
||||
});
|
||||
}
|
||||
|
||||
@ -85,6 +85,7 @@ ArtistCSS.propTypes = {
|
||||
error: PropTypes.string,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
artist: PropTypes.instanceOf(Immutable.Map),
|
||||
albums: PropTypes.instanceOf(Immutable.List),
|
||||
songs: PropTypes.instanceOf(Immutable.Map),
|
||||
|
@ -30,6 +30,30 @@ const songsMessages = defineMessages(messagesMap(Array.concat([], commonMessages
|
||||
* A single row for a single song in the songs table.
|
||||
*/
|
||||
class SongsTableRowCSSIntl extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Bind this
|
||||
this.onPlayClick = this.onPlayClick.bind(this);
|
||||
this.onPlayNextClick = this.onPlayNextClick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click on play button.
|
||||
*/
|
||||
onPlayClick() {
|
||||
$(this.refs.play).blur();
|
||||
this.props.playAction(this.props.song.get("id"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click on play next button.
|
||||
*/
|
||||
onPlayNextClick() {
|
||||
$(this.refs.playNext).blur();
|
||||
this.props.playNextAction(this.props.song.get("id"));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { formatMessage } = this.props.intl;
|
||||
|
||||
@ -40,11 +64,17 @@ class SongsTableRowCSSIntl extends Component {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<button styleName="play" title={formatMessage(songsMessages["app.common.play"])} onClick={() => this.props.playAction(this.props.song.get("id"))}>
|
||||
<button styleName="play" title={formatMessage(songsMessages["app.common.play"])} onClick={this.onPlayClick} ref="play">
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...songsMessages["app.common.play"]} />
|
||||
</span>
|
||||
<FontAwesome name="play-circle-o" aria-hidden="true" />
|
||||
</button>
|
||||
<button styleName="playNext" title={formatMessage(songsMessages["app.common.playNext"])} onClick={this.onPlayNextClick} ref="playNext">
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...songsMessages["app.common.playNext"]} />
|
||||
</span>
|
||||
<FontAwesome name="plus-circle" aria-hidden="true" />
|
||||
</button>
|
||||
</td>
|
||||
<td className="title">{this.props.song.get("name")}</td>
|
||||
@ -58,6 +88,7 @@ class SongsTableRowCSSIntl extends Component {
|
||||
}
|
||||
SongsTableRowCSSIntl.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
song: PropTypes.instanceOf(Immutable.Map).isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
@ -86,9 +117,9 @@ class SongsTableCSS extends Component {
|
||||
|
||||
// Build song rows
|
||||
let rows = [];
|
||||
const { playAction } = this.props;
|
||||
const { playAction, playNextAction } = this.props;
|
||||
displayedSongs.forEach(function (song) {
|
||||
rows.push(<SongsTableRow playAction={playAction} song={song} key={song.get("id")} />);
|
||||
rows.push(<SongsTableRow playAction={playAction} playNextAction={playNextAction} song={song} key={song.get("id")} />);
|
||||
});
|
||||
|
||||
// Handle login icon
|
||||
@ -134,6 +165,7 @@ class SongsTableCSS extends Component {
|
||||
}
|
||||
SongsTableCSS.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
songs: PropTypes.instanceOf(Immutable.List).isRequired,
|
||||
filterText: PropTypes.string,
|
||||
};
|
||||
@ -180,6 +212,7 @@ export default class FilterablePaginatedSongsTable extends Component {
|
||||
};
|
||||
const songsTableProps = {
|
||||
playAction: this.props.playAction,
|
||||
playNextAction: this.props.playNextAction,
|
||||
isFetching: this.props.isFetching,
|
||||
songs: this.props.songs,
|
||||
filterText: this.state.filterText,
|
||||
@ -197,6 +230,7 @@ export default class FilterablePaginatedSongsTable extends Component {
|
||||
}
|
||||
FilterablePaginatedSongsTable.propTypes = {
|
||||
playAction: PropTypes.func.isRequired,
|
||||
playNextAction: PropTypes.func.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.string,
|
||||
songs: PropTypes.instanceOf(Immutable.List).isRequired,
|
||||
|
@ -82,6 +82,32 @@ class WebPlayerCSSIntl extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Click handlers
|
||||
const onPrev = (function () {
|
||||
$(this.refs.prevBtn).blur();
|
||||
this.props.onPrev();
|
||||
}).bind(this);
|
||||
const onPlayPause = (function () {
|
||||
$(this.refs.playPauseBtn).blur();
|
||||
this.props.onPlayPause();
|
||||
}).bind(this);
|
||||
const onSkip = (function () {
|
||||
$(this.refs.nextBtn).blur();
|
||||
this.props.onSkip();
|
||||
}).bind(this);
|
||||
const onMute = (function () {
|
||||
$(this.refs.volumeBtn).blur();
|
||||
this.props.onMute();
|
||||
}).bind(this);
|
||||
const onRepeat = (function () {
|
||||
$(this.refs.repeatBtn).blur();
|
||||
this.props.onRepeat();
|
||||
}).bind(this);
|
||||
const onRandom = (function () {
|
||||
$(this.refs.randomBtn).blur();
|
||||
this.props.onRandom();
|
||||
}).bind(this);
|
||||
|
||||
return (
|
||||
<div id="row" styleName="webplayer">
|
||||
<div className="col-xs-12">
|
||||
@ -109,24 +135,24 @@ class WebPlayerCSSIntl extends Component {
|
||||
|
||||
<div className="row text-center" styleName="controls">
|
||||
<div className="col-xs-12">
|
||||
<button styleName="prevBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.previous"])} title={formatMessage(webplayerMessages["app.webplayer.previous"])} onClick={this.props.onPrev}>
|
||||
<button styleName="prevBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.previous"])} title={formatMessage(webplayerMessages["app.webplayer.previous"])} onClick={onPrev} ref="prevBtn">
|
||||
<FontAwesome name="step-backward" />
|
||||
</button>
|
||||
<button className="play" styleName="playPauseBtn" aria-label={formatMessage(webplayerMessages["app.common." + playPause])} title={formatMessage(webplayerMessages["app.common." + playPause])} onClick={this.props.onPlayPause}>
|
||||
<button className="play" styleName="playPauseBtn" aria-label={formatMessage(webplayerMessages["app.common." + playPause])} title={formatMessage(webplayerMessages["app.common." + playPause])} onClick={onPlayPause.bind(this)} ref="playPauseBtn">
|
||||
<FontAwesome name={playPause} />
|
||||
</button>
|
||||
<button styleName="nextBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.next"])} title={formatMessage(webplayerMessages["app.webplayer.next"])} onClick={this.props.onSkip}>
|
||||
<button styleName="nextBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.next"])} title={formatMessage(webplayerMessages["app.webplayer.next"])} onClick={onSkip} ref="nextBtn">
|
||||
<FontAwesome name="step-forward" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-xs-12">
|
||||
<button styleName="volumeBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.volume"])} title={formatMessage(webplayerMessages["app.webplayer.volume"])} onClick={this.props.onMute}>
|
||||
<button styleName="volumeBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.volume"])} title={formatMessage(webplayerMessages["app.webplayer.volume"])} onClick={onMute} ref="volumeBtn">
|
||||
<FontAwesome name={volumeIcon} />
|
||||
</button>
|
||||
<button styleName={repeatBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.repeat"])} title={formatMessage(webplayerMessages["app.webplayer.repeat"])} aria-pressed={this.props.isRepeat} onClick={this.props.onRepeat}>
|
||||
<button styleName={repeatBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.repeat"])} title={formatMessage(webplayerMessages["app.webplayer.repeat"])} aria-pressed={this.props.isRepeat} onClick={onRepeat} ref="repeatBtn">
|
||||
<FontAwesome name="repeat" />
|
||||
</button>
|
||||
<button styleName={randomBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.random"])} title={formatMessage(webplayerMessages["app.webplayer.random"])} aria-pressed={this.props.isRandom} onClick={this.props.onRandom}>
|
||||
<button styleName={randomBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.random"])} title={formatMessage(webplayerMessages["app.webplayer.random"])} aria-pressed={this.props.isRandom} onClick={onRandom} ref="randomBtn">
|
||||
<FontAwesome name="random" />
|
||||
</button>
|
||||
<button styleName="playlistBtn" aria-label={formatMessage(webplayerMessages["app.webplayer.playlist"])} title={formatMessage(webplayerMessages["app.webplayer.playlist"])}>
|
||||
|
@ -11,6 +11,7 @@ module.exports = {
|
||||
"app.common.loading": "Loading…", // Loading indicator
|
||||
"app.common.pause": "Pause", // Pause icon description
|
||||
"app.common.play": "Play", // Play icon description
|
||||
"app.common.playNext": "Play next", // "Play next icon descripton"
|
||||
"app.common.track": "{itemCount, plural, one {track} other {tracks}}", // Track
|
||||
"app.filter.filter": "Filter…", // Filtering input placeholder
|
||||
"app.filter.whatAreWeListeningToToday": "What are we listening to today?", // Description for the filter bar
|
||||
|
@ -11,6 +11,7 @@ module.exports = {
|
||||
"app.common.loading": "Chargement…", // Loading indicator
|
||||
"app.common.pause": "Pause", // Pause icon description
|
||||
"app.common.play": "Jouer", // PLay icon description
|
||||
"app.common.playNext": "Jouer après", // "Play next icon descripton"
|
||||
"app.common.track": "{itemCount, plural, one {piste} other {pistes}}", // Track
|
||||
"app.filter.filter": "Filtrer…", // Filtering input placeholder
|
||||
"app.filter.whatAreWeListeningToToday": "Que voulez-vous écouter aujourd'hui\u00a0?", // Description for the filter bar
|
||||
|
@ -49,6 +49,11 @@ const messages = [
|
||||
description: "Pause icon description",
|
||||
defaultMessage: "Pause",
|
||||
},
|
||||
{
|
||||
id: "app.common.playNext",
|
||||
defaultMessage: "Play next",
|
||||
description: "Play next icon descripton",
|
||||
},
|
||||
];
|
||||
|
||||
export default messages;
|
||||
|
@ -167,7 +167,7 @@ export default createReducer(initialState, {
|
||||
newState = state.set("isFetching", false).set("error", payload.error);
|
||||
|
||||
// Merge entities
|
||||
newState = newState.mergeIn(["entities"], payload.entities);
|
||||
newState = newState.mergeDeepIn(["entities"], payload.entities);
|
||||
|
||||
// Increment reference counter
|
||||
payload.refCountType.forEach(function (itemName) {
|
||||
|
@ -19,8 +19,8 @@ import {
|
||||
PUSH_SONG,
|
||||
POP_SONG,
|
||||
JUMP_TO_SONG,
|
||||
PLAY_PREVIOUS,
|
||||
PLAY_NEXT,
|
||||
PLAY_PREVIOUS_SONG,
|
||||
PLAY_NEXT_SONG,
|
||||
TOGGLE_RANDOM,
|
||||
TOGGLE_REPEAT,
|
||||
TOGGLE_MUTE,
|
||||
@ -77,32 +77,66 @@ export default createReducer(initialState, {
|
||||
},
|
||||
[PUSH_SONG]: (state, payload) => {
|
||||
// Push song to playlist
|
||||
const newPlaylist = state.get("playlist").insert(payload.index, payload.song);
|
||||
return state.set("playlist", newPlaylist);
|
||||
let newState = state;
|
||||
if (payload.index) {
|
||||
// If index is specified, insert it at this position
|
||||
newState = newState.set(
|
||||
"playlist",
|
||||
newState.get("playlist").insert(payload.index, payload.song)
|
||||
);
|
||||
if (payload.index <= newState.get("currentIndex")) { // "<=" because insertion is made before
|
||||
// If we insert before the current position in the playlist, we
|
||||
// update the current position to keep the currently played
|
||||
// music
|
||||
newState = newState.set(
|
||||
"currentIndex",
|
||||
Math.min(newState.get("currentIndex") + 1, newState.get("playlist").size)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Else, push at the end of the playlist
|
||||
newState = newState.set(
|
||||
"playlist",
|
||||
newState.get("playlist").push(payload.song)
|
||||
);
|
||||
}
|
||||
return newState;
|
||||
},
|
||||
[POP_SONG]: (state, payload) => {
|
||||
// Pop song from playlist
|
||||
return state.deleteIn(["playlist", payload.index]);
|
||||
let newState = state.deleteIn(["playlist", payload.index]);
|
||||
if (payload.index < state.get("currentIndex")) {
|
||||
// If we delete before the current position in the playlist, we
|
||||
// update the current position to keep the currently played
|
||||
// music
|
||||
newState = newState.set(
|
||||
"currentIndex",
|
||||
Math.max(newState.get("currentIndex") - 1, 0)
|
||||
);
|
||||
}
|
||||
return newState;
|
||||
},
|
||||
[JUMP_TO_SONG]: (state, payload) => {
|
||||
// Set current index
|
||||
const newCurrentIndex = state.get("playlist").findKey(x => x == payload.song);
|
||||
return state.set("currentIndex", newCurrentIndex);
|
||||
},
|
||||
[PLAY_PREVIOUS]: (state) => {
|
||||
[PLAY_PREVIOUS_SONG]: (state) => {
|
||||
const newIndex = state.get("currentIndex") - 1;
|
||||
if (newIndex < 0) {
|
||||
// If there is an overlow on the left of the playlist, just stop
|
||||
// playback
|
||||
// TODO: Behavior is not correct
|
||||
return stopPlayback(state);
|
||||
} else {
|
||||
return state.set("currentIndex", newIndex);
|
||||
}
|
||||
},
|
||||
[PLAY_NEXT]: (state) => {
|
||||
[PLAY_NEXT_SONG]: (state) => {
|
||||
const newIndex = state.get("currentIndex") + 1;
|
||||
if (newIndex > state.get("playlist").size) {
|
||||
// If there is an overflow, just stop playback
|
||||
// TODO: Behavior is not correct
|
||||
return stopPlayback(state);
|
||||
} else {
|
||||
// Else, play next item
|
||||
|
@ -35,6 +35,11 @@ $artMarginBottom: 10px;
|
||||
composes: play from "./Songs.scss";
|
||||
}
|
||||
|
||||
/* Play next button is based on the one in Songs list. */
|
||||
.playNext {
|
||||
composes: playNext from "./Songs.scss";
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.nameRow h2 {
|
||||
margin-top: 0;
|
||||
|
@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Style for Songs component.
|
||||
*/
|
||||
.play {
|
||||
.play,
|
||||
.playNext {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-align: center;
|
||||
|
@ -45,7 +45,7 @@ class ArtistPageIntl extends Component {
|
||||
const error = handleErrorI18nObject(this.props.error, formatMessage, artistMessages);
|
||||
|
||||
return (
|
||||
<Artist playAction={this.props.actions.playSong} isFetching={this.props.isFetching} error={error} artist={this.props.artist} albums={this.props.albums} songs={this.props.songs} />
|
||||
<Artist playAction={this.props.actions.playSong} playNextAction={this.props.actions.pushSong} isFetching={this.props.isFetching} error={error} artist={this.props.artist} albums={this.props.albums} songs={this.props.songs} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class SongsPageIntl extends Component {
|
||||
const error = handleErrorI18nObject(this.props.error, formatMessage, songsMessages);
|
||||
|
||||
return (
|
||||
<Songs playAction={this.props.actions.playSong} isFetching={this.props.isFetching} error={error} songs={this.props.songsList} pagination={pagination} />
|
||||
<Songs playAction={this.props.actions.playSong} playNextAction={this.props.actions.pushSong} isFetching={this.props.isFetching} error={error} songs={this.props.songsList} pagination={pagination} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ class WebPlayer extends Component {
|
||||
// Use a lambda to ensure no first argument is passed to
|
||||
// togglePlaying
|
||||
onPlayPause: (() => this.props.actions.togglePlaying()),
|
||||
onPrev: this.props.actions.playPrevious,
|
||||
onSkip: this.props.actions.playNext,
|
||||
onPrev: this.props.actions.playPreviousSong,
|
||||
onSkip: this.props.actions.playNextSong,
|
||||
onRandom: this.props.actions.toggleRandom,
|
||||
onRepeat: this.props.actions.toggleRepeat,
|
||||
onMute: this.props.actions.toggleMute,
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user