diff --git a/mopidy_iris/__init__.py b/mopidy_iris/__init__.py index 26b280aa..e54741b9 100755 --- a/mopidy_iris/__init__.py +++ b/mopidy_iris/__init__.py @@ -15,7 +15,7 @@ __version__ = '2.11.3' # # Loads config and gets the party started. Initiates any additional frontends, etc. ## -class IrisExtension( ext.Extension ): +class Extension( ext.Extension ): dist_name = 'Mopidy-Iris' ext_name = 'iris' @@ -26,9 +26,11 @@ class IrisExtension( ext.Extension ): return config.read(conf_file) def get_config_schema(self): - schema = super(IrisExtension, self).get_config_schema() - schema['debug'] = config.Boolean() + schema = config.ConfigSchema(self.ext_name) + schema['enabled'] = config.Boolean() schema['pusherport'] = config.String() + schema['country'] = config.String() + schema['locale'] = config.String() return schema def setup(self, registry): diff --git a/mopidy_iris/ext.conf b/mopidy_iris/ext.conf index 71f06613..8cd62fcf 100755 --- a/mopidy_iris/ext.conf +++ b/mopidy_iris/ext.conf @@ -1,4 +1,5 @@ [iris] enabled = true -debug = false -pusherport = 6681 \ No newline at end of file +pusherport = 6681 +country = NZ +locale = en_NZ \ No newline at end of file diff --git a/mopidy_iris/frontend.py b/mopidy_iris/frontend.py index da07748b..d08491be 100755 --- a/mopidy_iris/frontend.py +++ b/mopidy_iris/frontend.py @@ -189,6 +189,17 @@ class IrisFrontend(pykka.ThreadingActor, CoreListener): def get_spotify_token( self ): return self.spotify_token + + # get our config values + def get_config( self ): + all_config = self.config + config = { + "spotify_username": all_config['spotify']['username'], + "country": all_config['iris']['country'], + "locale": all_config['iris']['locale'] + } + return config + ## # Get Spotmop version, and check for updates diff --git a/mopidy_iris/pusher.py b/mopidy_iris/pusher.py index 8adb767f..13047a14 100755 --- a/mopidy_iris/pusher.py +++ b/mopidy_iris/pusher.py @@ -188,6 +188,15 @@ class PusherWebsocketHandler(tornado.websocket.WebSocketHandler): { 'error': 'Could not send to that connection, does not exist' } ) + # fetch our pusher connections + elif messageJson['action'] == 'get_config': + send_message( + self.connectionid, + 'response', + messageJson['request_id'], + { 'config': self.frontend.get_config() } + ) + # fetch our pusher connections elif messageJson['action'] == 'get_connections': @@ -266,7 +275,7 @@ class PusherWebsocketHandler(tornado.websocket.WebSocketHandler): { 'version': version } ) - # get system version and check for upgrade + # perform upgrade elif messageJson['action'] == 'upgrade': version = self.frontend.get_version() upgrade_successful = self.frontend.perform_upgrade() @@ -290,7 +299,7 @@ class PusherWebsocketHandler(tornado.websocket.WebSocketHandler): { 'error': 'Unhandled action' } ) - logger.debug( 'Pusher: Message received from '+ self.connectionid ) + logger.debug( 'Pusher: Unhandled message received from '+ self.connectionid ) # connection closed def on_close(self): diff --git a/setup.py b/setup.py index 446656a7..3df0588c 100755 --- a/setup.py +++ b/setup.py @@ -37,7 +37,7 @@ setup( ], entry_points={ 'mopidy.ext': [ - 'iris = mopidy_iris:IrisExtension', + 'iris = mopidy_iris:Extension', ], }, ) diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js index 477c24f1..b174b7df 100755 --- a/src/js/bootstrap.js +++ b/src/js/bootstrap.js @@ -49,8 +49,6 @@ var initialState = { }, spotify: { connected: false, - country: 'NZ', - locale: 'en_NZ', me: false }, ui: { diff --git a/src/js/components/Modal/CreatePlaylistModal.js b/src/js/components/Modal/CreatePlaylistModal.js index 7033218c..bf009fe0 100755 --- a/src/js/components/Modal/CreatePlaylistModal.js +++ b/src/js/components/Modal/CreatePlaylistModal.js @@ -74,7 +74,9 @@ export default class CreatePlaylistModal extends React.Component{ Public - +
+ +
) diff --git a/src/js/components/Modal/EditPlaylistModal.js b/src/js/components/Modal/EditPlaylistModal.js index a54c5da6..c3431822 100755 --- a/src/js/components/Modal/EditPlaylistModal.js +++ b/src/js/components/Modal/EditPlaylistModal.js @@ -53,7 +53,9 @@ export default class EditPlaylistModal extends React.Component{ Public - +
+ +
) diff --git a/src/js/components/Modal/EditRadioModal.js b/src/js/components/Modal/EditRadioModal.js index 2e8ebe2b..cab81b9f 100755 --- a/src/js/components/Modal/EditRadioModal.js +++ b/src/js/components/Modal/EditRadioModal.js @@ -24,13 +24,12 @@ export default class EditRadioModal extends React.Component{ this.props.spotifyActions.resolveRadioSeeds(this.props.radio) } - save(){ - this.props.pusherActions.startRadio(this.state.seeds) - this.props.uiActions.closeModal() - } - - stop(){ - this.props.pusherActions.stopRadio() + handleSubmit(e){ + if (this.state.enabled){ + this.props.pusherActions.startRadio(this.state.seeds) + }else{ + this.props.pusherActions.stopRadio() + } this.props.uiActions.closeModal() } @@ -68,7 +67,7 @@ export default class EditRadioModal extends React.Component{ renderSeeds(){ var seeds = [] - if (this.state.enabled && this.state.seeds){ + if (this.state.seeds){ for (var i = 0; i < this.state.seeds.length; i++){ var uri = this.state.seeds[i] if (uri){ @@ -98,37 +97,35 @@ export default class EditRadioModal extends React.Component{ } return ( -
- { - seeds.map((seed,index) => { - return ( -
- {seed.unresolved ? {seed.uri} : {seed.name} } -  ({seed.type}) - this.removeSeed(seed.uri)} /> -
- ) - }) - } +
+
+ { + seeds.map((seed,index) => { + return ( +
+ {seed.unresolved ? {seed.uri} : {seed.name} } +  ({seed.type}) + this.removeSeed(seed.uri)} /> +
+ ) + }) + } +
) } - renderActions(){ - if (this.state.enabled){ - return ( - - - - - ) - }else{ - return ( - - - - ) - } + renderAddSeeds(){ + return ( +
+ this.setState({uri: e.target.value})} + value={this.state.uri} /> + +
+ ) } render(){ @@ -136,22 +133,23 @@ export default class EditRadioModal extends React.Component{

Edit radio

-

Current seeds

- {this.renderSeeds()} - -
-

Add seeds

-
- this.setState({uri: e.target.value})} - value={this.state.uri} /> - + this.handleSubmit(e)}> +
+
+ {this.state.enabled ? this.renderSeeds() : null} + {this.state.enabled ? this.renderAddSeeds() : null} +
- {this.renderActions()} +
diff --git a/src/js/index.js b/src/js/index.js index d80f10db..d1911ad4 100755 --- a/src/js/index.js +++ b/src/js/index.js @@ -39,16 +39,17 @@ import LibraryLocalDirectory from './views/library/LibraryLocalDirectory' // setup our analytics tracking ReactGA.initialize('UA-64701652-3'); -function logPageView() { +function handleUpdate() { ReactGA.set({ page: window.location.hash }) ReactGA.pageview(window.location.hash) + $(window).scrollTop(0) } global.baseURL = '/' ReactDOM.render( - + diff --git a/src/js/services/pusher/middleware.js b/src/js/services/pusher/middleware.js index 00fb9715..7fd8942e 100755 --- a/src/js/services/pusher/middleware.js +++ b/src/js/services/pusher/middleware.js @@ -1,7 +1,8 @@ -var pusherActions = require('./actions.js') -var uiActions = require('../ui/actions.js') var helpers = require('../../helpers.js') +var uiActions = require('../ui/actions.js') +var pusherActions = require('./actions.js') +var spotifyActions = require('../spotify/actions.js') const PusherMiddleware = (function(){ @@ -103,12 +104,6 @@ const PusherMiddleware = (function(){ socket.onopen = () => { store.dispatch({ type: 'PUSHER_CONNECTED', connection: connection }); store.dispatch({ type: 'PUSHER_SET_USERNAME', username: connection.username }); - request({ action: 'get_radio' }) - .then( - response => { - store.dispatch({ type: 'RADIO', data: response.data }) - } - ) }; socket.onmessage = (message) => { @@ -119,10 +114,29 @@ const PusherMiddleware = (function(){ break; case 'PUSHER_CONNECTED': + request({ action: 'get_config' }) + .then( + response => { + store.dispatch({ type: 'CONFIG', config: response.data.config }) + if (response.data.config.spotify_username){ + store.dispatch(spotifyActions.getUser('spotify:user:'+response.data.config.spotify_username)) + } + var spotify = store.getState().spotify + if (!spotify.country || !spotify.locale){ + store.dispatch({ type: 'SPOTIFY_SET_CONFIG', config: response.data.config }) + } + } + ) request({ action: 'get_version' }) .then( response => { - store.dispatch({ type: 'VERSION', data: response.data }) + store.dispatch({ type: 'VERSION', version: response.data.version }) + } + ) + request({ action: 'get_radio' }) + .then( + response => { + store.dispatch({ type: 'RADIO', radio: response.data.radio }) } ) return next(action); @@ -141,7 +155,7 @@ const PusherMiddleware = (function(){ }else{ store.dispatch( uiActions.createNotification('Upgrade failed, please upgrade manually','bad') ) } - store.dispatch({ type: 'VERSION', data: response.data }) + store.dispatch({ type: 'VERSION', version: response.data.version }) } ) return next(action); diff --git a/src/js/services/pusher/reducer.js b/src/js/services/pusher/reducer.js index 8335e1f1..462f68e4 100755 --- a/src/js/services/pusher/reducer.js +++ b/src/js/services/pusher/reducer.js @@ -39,7 +39,7 @@ export default function reducer(pusher = {}, action){ case 'VERSION': return Object.assign({}, pusher, { - version: action.data.version, + version: action.version, upgrading: false }); diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index 85a78b30..7dd4cd4e 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -1,4 +1,5 @@ +var uiActions = require('../../services/ui/actions.js') var helpers = require('../../helpers.js') /** @@ -39,6 +40,7 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false }, (xhr, status, error) => { console.error( endpoint+' failed', xhr.responseText) + dispatch(uiActions.createNotification(xhr.responseText,'bad')) reject(error) } ) @@ -98,6 +100,7 @@ function refreshToken( dispatch, getState ){ }, error => { dispatch({ type: 'SPOTIFY_DISCONNECTED' }) + dispatch(uiActions.createNotification('Could not refresh token','bad')) console.error('Could not refresh token', error) reject(error) } @@ -124,6 +127,7 @@ function refreshToken( dispatch, getState ){ }, error => { dispatch({ type: 'SPOTIFY_DISCONNECTED' }) + dispatch(uiActions.createNotification('Could not refresh token','bad')) console.error('Could not refresh token', error) reject(error) } diff --git a/src/js/services/spotify/middleware.js b/src/js/services/spotify/middleware.js index 939e43de..6081e4eb 100755 --- a/src/js/services/spotify/middleware.js +++ b/src/js/services/spotify/middleware.js @@ -93,8 +93,8 @@ const SpotifyMiddleware = (function(){ next(action) // only resolve if radio is enabled - if( action.data.radio.enabled ){ - store.dispatch(spotifyActions.resolveRadioSeeds(action.data.radio)) + if( action.radio.enabled ){ + store.dispatch(spotifyActions.resolveRadioSeeds(action.radio)) } break diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js index 914f242b..33e3e84a 100755 --- a/src/js/services/spotify/reducer.js +++ b/src/js/services/spotify/reducer.js @@ -12,6 +12,9 @@ export default function reducer(spotify = {}, action){ case 'SPOTIFY_DISCONNECTED': return Object.assign({}, spotify, { connected: false, connecting: false }) + case 'SPOTIFY_SET_CONFIG': + return Object.assign({}, spotify, action.config) + case 'PUSHER_SPOTIFY_TOKEN': if( spotify.authorized ) return spotify; return Object.assign({}, spotify, { diff --git a/src/js/services/ui/middleware.js b/src/js/services/ui/middleware.js index fa44b99d..6f6c9d2a 100755 --- a/src/js/services/ui/middleware.js +++ b/src/js/services/ui/middleware.js @@ -209,9 +209,9 @@ const UIMiddleware = (function(){ next(action) break - case 'PUSHER_VERSION': - if( action.data.version.upgrade_available ) - store.dispatch( uiActions.createNotification( 'Version '+action.data.version.latest+' is available. See settings to upgrade.' ) ) + case 'VERSION': + if( action.version.upgrade_available ) + store.dispatch( uiActions.createNotification( 'Version '+action.version.latest+' is available. See settings to upgrade.' ) ) next( action ) break diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index 9730f6f3..32e969b2 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -13,6 +13,9 @@ export default function reducer(ui = {}, action){ case 'UI_SET': return Object.assign({}, ui, action.data) + case 'CONFIG': + return Object.assign({}, ui, { config: action.config }) + case 'TOGGLE_SIDEBAR': var new_state = !ui.sidebar_open if( typeof(action.new_state) !== 'undefined' ) new_state = action.new_state @@ -118,7 +121,7 @@ export default function reducer(ui = {}, action){ case 'RADIO': case 'START_RADIO': - return Object.assign({}, ui, { seeds_resolved: false }, { radio: action.data.radio }) + return Object.assign({}, ui, { seeds_resolved: false }, { radio: action.radio }) case 'RADIO_SEEDS_RESOLVED': var radio = Object.assign({}, ui.radio, { resolved_seeds: action.resolved_seeds }) diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js index 47ee71c8..c114149b 100755 --- a/src/js/views/Settings.js +++ b/src/js/views/Settings.js @@ -34,7 +34,8 @@ class Settings extends React.Component{ resetAllSettings(){ localStorage.clear(); - window.location.reload(true); + window.location = '#' + window.location.reload(true) return false; } @@ -80,21 +81,33 @@ class Settings extends React.Component{ } renderSpotifyUser(){ - if( this.props.spotify.me && this.props.spotify.authorized ){ + + var user = null + if (this.props.spotify.me && this.props.spotify.authorized){ + user = this.props.spotify.me + } else if (this.props.ui.config && this.props.ui.config.spotify_username){ + if (this.props.ui.users && typeof(this.props.ui.users['spotify:user:'+this.props.ui.config.spotify_username]) !== 'undefined'){ + user = this.props.ui.users['spotify:user:'+this.props.ui.config.spotify_username] + } + } + + if (user){ return ( - - + + - { this.props.spotify.me.display_name ? this.props.spotify.me.display_name : this.props.spotify.me.id } + {user.display_name ? user.display_name : user.username} + {!this.props.spotify.authorized ?  (As defined in config file) : null} ) - }else{ + } else { return ( - Default user (As defined in mopidy.config) + Default user +  (As defined in config file) ) diff --git a/src/scss/components/_header.scss b/src/scss/components/_header.scss index 9c65ab3b..114dd7a9 100755 --- a/src/scss/components/_header.scss +++ b/src/scss/components/_header.scss @@ -32,7 +32,8 @@ main { background: transparent; font-size: 14px; font-weight: 600; - padding: 14px 10px; + padding: 13px 10px; + line-height: 24px; text-transform: uppercase; } } diff --git a/src/scss/components/_modal.scss b/src/scss/components/_modal.scss index f11e5db7..4b136c45 100755 --- a/src/scss/components/_modal.scss +++ b/src/scss/components/_modal.scss @@ -133,7 +133,6 @@ &.edit_radio { form { - padding-top: 60px; .field { position: relative; margin-top: 10px; @@ -141,7 +140,11 @@ position: absolute; top: 5px; right: 0; - padding: 10px 12px; + padding: 14px; + } + input[type="text"]{ + font-size: 14px; + padding: 16px 18px; } } } diff --git a/src/scss/components/_notifications.scss b/src/scss/components/_notifications.scss index fe413312..15d310a2 100755 --- a/src/scss/components/_notifications.scss +++ b/src/scss/components/_notifications.scss @@ -6,7 +6,8 @@ left: 0; right: 0; text-align: center; - z-index: 100; + z-index: 99; + pointer-events: none; .notification { display: inline-block; @@ -15,6 +16,7 @@ padding: 12px 32px 12px 18px; margin: 0 0.5px; color: #FFFFFF; + pointer-events: all; &:first-child { border-top-left-radius: 50px; diff --git a/src/scss/global/_core.scss b/src/scss/global/_core.scss index 7664675b..8ec5593b 100755 --- a/src/scss/global/_core.scss +++ b/src/scss/global/_core.scss @@ -115,6 +115,8 @@ h4 { .no-bottom-padding { padding-bottom: 0 !important; } .no-right-padding { padding-right: 0 !important; } .no-left-padding { padding-left: 0 !important; } +.no-top-margin { margin-top: 0 !important; } +.no-bottom-margin { margin-bottom: 0 !important; } .top-padding { padding-top: 20px; } .bottom-padding { padding-bottom: 20px; } diff --git a/src/scss/global/_forms.scss b/src/scss/global/_forms.scss index 23578296..be22739e 100755 --- a/src/scss/global/_forms.scss +++ b/src/scss/global/_forms.scss @@ -47,6 +47,10 @@ input[type="submit"] { &.large { padding: 16px 24px; + + @include responsive( $bp_medium ){ + padding: 10px 20px; + } } &.primary { diff --git a/src/scss/views/_artist.scss b/src/scss/views/_artist.scss index 6dacd7bb..fe0f0bc3 100755 --- a/src/scss/views/_artist.scss +++ b/src/scss/views/_artist.scss @@ -84,9 +84,7 @@ @include responsive( $bp_medium ){ .intro { - - padding: 50px 30px 0 30px; - margin: 0 0 140px 0; + padding: 50px 30px 60px 30px; .parallax { height: 100%; @@ -107,26 +105,48 @@ .heading-wrapper { height: auto; + position: static; - .heading, - .sub-views { - position: relative; + .heading { + position: static; bottom: auto; left: auto; + + h1 { + position: relative; + text-align: center; + padding: 15px 0; + } + + .sub-views { + position: absolute; + bottom: 0; + left: 20px; + right: 20px; + } } } .details-wrapper { padding: 0; - position: absolute; + position: relative; left: 0; right: 0; - padding: 30px; - background: $faint_grey; - z-index: 2; + padding: 20px 0; + z-index: 3; + + .actions { + text-align: center; + margin: 0; + float: none; + + button { + margin: 0 3px; + } + } .details { - clear: both; + display: none; } } }