From 79090edd2c26578c10bd443989d38d6e5930c4cb Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Tue, 18 Apr 2017 04:44:39 +1200 Subject: [PATCH] Overhaul radio UI, fixes #93 --- mopidy_iris/core.py | 29 ++++++- src/assets/radio-overlay.png | Bin 0 -> 24913 bytes src/js/components/FullPlayer.js | 9 ++- src/js/components/Modal/EditRadioModal.js | 92 +++++++++++----------- src/js/services/pusher/actions.js | 7 ++ src/js/services/pusher/middleware.js | 38 ++++----- src/js/services/spotify/actions.js | 15 ++-- src/js/views/Queue.js | 1 + src/scss/components/_lists.scss | 17 ++++ src/scss/components/_modal.scss | 21 ++--- src/scss/components/_player.scss | 12 +++ src/scss/global/_core.scss | 1 - src/scss/global/_forms.scss | 14 ++++ 13 files changed, 169 insertions(+), 87 deletions(-) create mode 100755 src/assets/radio-overlay.png diff --git a/mopidy_iris/core.py b/mopidy_iris/core.py index d5719948..2b030442 100755 --- a/mopidy_iris/core.py +++ b/mopidy_iris/core.py @@ -260,9 +260,11 @@ class IrisCore(object): # no uris means we can't play radio if not uris: + self.radio['enabled'] = 0 return { 'status': 0, - 'message': 'No recommendations found' + 'message': 'No recommendations found', + 'radio': self.radio } # if we got recommendations @@ -279,6 +281,31 @@ class IrisCore(object): return self.get_radio({}) + def update_radio(self, data): + self.radio = data + self.radio['enabled'] = 1; + + uris = self.load_more_tracks() + + # no uris means we can't play radio + if not uris: + self.radio['enabled'] = 0 + return { + 'status': 0, + 'message': 'No recommendations found', + 'radio': self.radio + } + + # if we got recommendations + else: + self.core.tracklist.add( uris = uris ) + self.broadcast({ + 'type': 'radio_updated', + 'radio': self.radio + }) + + return self.get_radio({}) + def stop_radio(self, data): self.radio = { diff --git a/src/assets/radio-overlay.png b/src/assets/radio-overlay.png new file mode 100755 index 0000000000000000000000000000000000000000..2213b532b11b01d74f9b2f9ea5d51fb2288ba56a GIT binary patch literal 24913 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 O@I*~Vwc?>o^#224SMiwu literal 0 HcmV?d00001 diff --git a/src/js/components/FullPlayer.js b/src/js/components/FullPlayer.js index caaf8573..4b5f6f96 100755 --- a/src/js/components/FullPlayer.js +++ b/src/js/components/FullPlayer.js @@ -69,6 +69,7 @@ class FullPlayer extends React.Component{ !this.props.current_track.album.images ){ return ( + {this.props.radio_enabled ? : null} ) @@ -78,6 +79,7 @@ class FullPlayer extends React.Component{ if( this.props.current_track.album.uri ) link = '/album/'+this.props.current_track.album.uri return ( this.handleContextMenu(e,this.props.current_track.album)}> + {this.props.radio_enabled ? : null} ) @@ -90,8 +92,10 @@ class FullPlayer extends React.Component{ { this.renderArtwork() }

-
{ this.props.current_track ? this.props.current_track.name : - }
- { this.props.current_track ? : } +
+ {this.props.current_track ? this.props.current_track.name : -} +
+ {this.props.current_track ? : }
@@ -135,6 +139,7 @@ class FullPlayer extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + radio_enabled: (state.ui.radio && state.ui.radio.enabled ? true : false), current_track: state.ui.current_track, play_state: state.mopidy.play_state, time_position: state.mopidy.time_position, diff --git a/src/js/components/Modal/EditRadioModal.js b/src/js/components/Modal/EditRadioModal.js index 1b60aab0..d14a4d6a 100755 --- a/src/js/components/Modal/EditRadioModal.js +++ b/src/js/components/Modal/EditRadioModal.js @@ -12,7 +12,8 @@ export default class EditRadioModal extends React.Component{ this.state = { enabled: false, seeds: [], - uri: '' + uri: '', + error_message: null } } @@ -24,26 +25,39 @@ export default class EditRadioModal extends React.Component{ this.props.spotifyActions.resolveRadioSeeds(this.props.radio) } - handleSubmit(e){ - if (this.state.enabled){ - this.props.pusherActions.startRadio(this.state.seeds) - }else{ - this.props.pusherActions.stopRadio() - } + handleStart(e){ + e.preventDefault() + this.props.pusherActions.startRadio(this.state.seeds) + this.props.uiActions.closeModal() + } + + handleUpdate(e){ + e.preventDefault() + this.props.pusherActions.updateRadio(this.state.seeds) + this.props.uiActions.closeModal() + } + + handleStop(e){ + e.preventDefault() + this.props.pusherActions.stopRadio() this.props.uiActions.closeModal() } addSeed(){ - if (this.state.uri == '') return null + if (this.state.uri == ''){ + this.setState({error_message: 'Cannot be empty'}) + return null + } var seeds = Object.assign([],this.state.seeds) var uris = this.state.uri.split(',') for (var i = 0; i < uris.length; i++){ - if (seeds.indexOf(uris[i]) <= -1){ - seeds.push(uris[i]) + if (seeds.indexOf(uris[i]) > -1){ + this.setState({error_message: 'URI already added'}) } else { - this.props.uiActions.createNotification(uris[i]+' already added','bad') + seeds.push(uris[i]) + this.setState({error_message: null}) } } @@ -71,8 +85,8 @@ export default class EditRadioModal extends React.Component{ for (var i = 0; i < this.state.seeds.length; i++){ var uri = this.state.seeds[i] if (uri){ - if (helpers.uriType(uri) == 'artist' && this.props.artists){ - if (this.props.artists.hasOwnProperty(uri)){ + if (helpers.uriType(uri) == 'artist'){ + if (this.props.artists && this.props.artists.hasOwnProperty(uri)){ seeds.push(this.props.artists[uri]) } else { seeds.push({ @@ -81,8 +95,8 @@ export default class EditRadioModal extends React.Component{ uri: uri }) } - } else if (helpers.uriType(uri) == 'track' && this.props.tracks){ - if (this.props.tracks.hasOwnProperty(uri)){ + } else if (helpers.uriType(uri) == 'track'){ + if (this.props.tracks && this.props.tracks.hasOwnProperty(uri)){ seeds.push(this.props.tracks[uri]) } else { seeds.push({ @@ -105,7 +119,9 @@ export default class EditRadioModal extends React.Component{
{seed.unresolved ? {seed.uri} : {seed.name} }  ({seed.type}) - this.removeSeed(seed.uri)} /> +
) }) @@ -115,41 +131,29 @@ export default class EditRadioModal extends React.Component{ ) } - renderAddSeeds(){ - return ( -
- this.setState({uri: e.target.value})} - value={this.state.uri} /> - -
- ) - } - render(){ return (
-

Edit radio

+

Manage radio

-
this.handleSubmit(e)}> -
- + + {this.renderSeeds()} + +
+ this.setState({uri: e.target.value, error_message: null})} + value={this.state.uri} /> + + {this.state.error_message ? {this.state.error_message} : null}
- {this.state.enabled ? this.renderSeeds() : null} - {this.state.enabled ? this.renderAddSeeds() : null} -
- + {this.state.enabled ? : null} + {this.state.enabled ? : }
diff --git a/src/js/services/pusher/actions.js b/src/js/services/pusher/actions.js index 6e9b6eb1..2db1d776 100755 --- a/src/js/services/pusher/actions.js +++ b/src/js/services/pusher/actions.js @@ -76,6 +76,13 @@ export function startRadio( uris ){ } } +export function updateRadio( uris ){ + return { + type: 'PUSHER_UPDATE_RADIO', + uris: uris + } +} + export function stopRadio(){ return { type: 'PUSHER_STOP_RADIO' diff --git a/src/js/services/pusher/middleware.js b/src/js/services/pusher/middleware.js index a7d4563e..f231f8bf 100755 --- a/src/js/services/pusher/middleware.js +++ b/src/js/services/pusher/middleware.js @@ -243,7 +243,16 @@ const PusherMiddleware = (function(){ break case 'PUSHER_START_RADIO': - store.dispatch(uiActions.createNotification('Starting radio...')) + case 'PUSHER_UPDATE_RADIO': + if (action.type == 'PUSHER_UPDATE_RADIO'){ + var method = 'update_radio' + var process_text = 'Updating radio' + } else { + var method = 'start_radio' + var process_text = 'Starting radio' + } + + store.dispatch(uiActions.startProcess('PUSHER_RADIO', process_text)) var data = { seed_artists: [], @@ -264,19 +273,11 @@ const PusherMiddleware = (function(){ break; } } - - // we don't need to wait for response, as change will be broadcast - request(store, 'start_radio', data) - break - case 'PUSHER_RADIO_STARTED': - var data = { - type: 'browser_notification', - title: 'Radio', - body: 'Radio mode started', - icon: (store.getState().ui.current_track ? helpers.getTrackIcon( store.getState().ui.current_track ) : false) - } - store.dispatch( pusherActions.deliverBroadcast(data) ) + request(store, method, data) + .then(response => { + store.dispatch(uiActions.stopProcess('PUSHER_RADIO')) + }) break case 'PUSHER_STOP_RADIO': @@ -292,22 +293,11 @@ const PusherMiddleware = (function(){ request(store, 'stop_radio', data) break - case 'PUSHER_RADIO_STOPPED': - var data = { - type: 'browser_notification', - title: 'Radio', - body: 'Radio mode stopped', - icon: (store.getState().ui.current_track ? helpers.getTrackIcon( store.getState().ui.current_track ) : false) - } - store.dispatch( pusherActions.deliverBroadcast(data) ) - break - case 'PUSHER_BROWSER_NOTIFICATION': store.dispatch(uiActions.createBrowserNotification(action)) break case 'PUSHER_RESTART': - // Hard reload. This doesn't strictly clear the cache, but our compiler's // cache buster should handle that window.location.reload(true); diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index 6b334bec..4fd0cb95 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -528,13 +528,16 @@ export function resolveRadioSeeds( radio ){ artist_ids += helpers.getFromUri('artistid', radio.seed_artists[i]) } - sendRequest( dispatch, getState, 'artists/'+ artist_ids ) + sendRequest( dispatch, getState, 'artists?ids='+ artist_ids ) .then( response => { - if (!(response instanceof Array)) response = [response] - dispatch({ - type: 'ARTISTS_LOADED', - artists: response - }) + if (response && response.artists){ + dispatch({ + type: 'ARTISTS_LOADED', + artists: response.artists + }) + } else { + console.error('No Spotify artists returned', artist_ids) + } }) } diff --git a/src/js/views/Queue.js b/src/js/views/Queue.js index b28302cd..b1a589b4 100755 --- a/src/js/views/Queue.js +++ b/src/js/views/Queue.js @@ -62,6 +62,7 @@ class Queue extends React.Component{