From c34c1870070dd21feddf083cd2851984866af571 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 4 Aug 2017 09:19:19 +1200 Subject: [PATCH] Revamp of settings to contain more granular control of services --- src/js/bootstrap.js | 2 + src/js/components/Settings/Debug.js | 196 ++++++++++ src/js/components/Settings/Services.js | 213 +++++++++++ src/js/components/Settings/System.js | 194 ++++++++++ src/js/index.js | 4 +- src/js/services/core/middleware.js | 2 + src/js/services/lastfm/actions.js | 14 + src/js/services/lastfm/reducer.js | 7 + src/js/services/localstorage/middleware.js | 1 + src/js/services/pusher/middleware.js | 10 + src/js/views/Debug.js | 228 ----------- src/js/views/Settings.js | 423 +++------------------ src/scss/app.scss | 1 + src/scss/components/_sub-views.scss | 26 ++ src/scss/global/_forms.scss | 4 +- src/scss/views/_artist.scss | 25 -- src/scss/views/_settings.scss | 12 +- 17 files changed, 741 insertions(+), 621 deletions(-) create mode 100755 src/js/components/Settings/Debug.js create mode 100755 src/js/components/Settings/Services.js create mode 100755 src/js/components/Settings/System.js delete mode 100755 src/js/views/Debug.js create mode 100755 src/scss/components/_sub-views.scss diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js index 8fedb251..d61ef5b8 100755 --- a/src/js/bootstrap.js +++ b/src/js/bootstrap.js @@ -55,6 +55,7 @@ var initialState = { } }, lastfm: { + connected: false, album: {}, artist: {}, track: {} @@ -62,6 +63,7 @@ var initialState = { spotify: { enabled: true, connected: false, + authentication_provider: 'backend', me: false, autocomplete_results: {}, authorization_url: 'https://jamesbarnsley.co.nz/auth_v2.php' diff --git a/src/js/components/Settings/Debug.js b/src/js/components/Settings/Debug.js new file mode 100755 index 00000000..c85c7225 --- /dev/null +++ b/src/js/components/Settings/Debug.js @@ -0,0 +1,196 @@ + +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import { Link, hashHistory } from 'react-router' +import { bindActionCreators } from 'redux' +import FontAwesome from 'react-fontawesome' + +import SpotifyAuthenticationFrame from '../SpotifyAuthenticationFrame' + +import * as uiActions from '../../services/ui/actions' +import * as pusherActions from '../../services/pusher/actions' +import * as mopidyActions from '../../services/mopidy/actions' +import * as spotifyActions from '../../services/spotify/actions' + +class Debug extends React.Component{ + + constructor(props) { + super(props); + this.state = { + mopidy_call: 'playlists.asList', + mopidy_data: '{}', + pusher_data: '{"method":"get_config"}', + access_token: (this.props.access_token ? this.props.access_token : '') + } + } + + callMopidy(e){ + e.preventDefault() + this.props.mopidyActions.debug( this.state.mopidy_call, JSON.parse(this.state.mopidy_data) ) + } + + callPusher(e){ + e.preventDefault() + this.props.pusherActions.debug( JSON.parse(this.state.pusher_data) ) + } + + render(){ + return ( +
+

User interface

+
+
+
Debug
+
+ +
+
+
+
Logging
+
+ + + +
+
+
+
+
+ this.props.uiActions.createNotification('Test notification')}>Create notification + this.props.uiActions.startProcess('test_process', 'Test process')}>Start process + this.props.uiActions.stopProcess('test_process')}>Stop process +
+
+
+ +

Mopidy

+
this.callMopidy(e)}> +
+
Call
+
+ this.setState({ mopidy_call: e.target.value })} + value={ this.state.mopidy_call } /> +
+
+
+
Data
+
+ +
+
+
+
+
+ +
+
+
+ +

Pusher

+
this.callPusher(e)}> +
+
Examples
+
+ +
+
+
+
Data
+
+ +
+
+
+
+
+ +
+
+
+ +

Response

+
+					{ this.props.debug_response ? JSON.stringify(this.props.debug_response, null, 2) : null }
+				
+ +
+ ); + } +} + + +/** + * Export our component + * + * We also integrate our global store, using connect() + **/ + +const mapStateToProps = (state, ownProps) => { + return { + connection_id: state.pusher.connection_id, + access_token: (state.spotify.access_token ? state.spotify.access_token : ''), + log_actions: (state.ui.log_actions ? state.ui.log_actions : false), + log_pusher: (state.ui.log_pusher ? state.ui.log_pusher : false), + log_mopidy: (state.ui.log_mopidy ? state.ui.log_mopidy : false), + debug_info: (state.ui.debug_info ? state.ui.debug_info : false), + debug_response: state.ui.debug_response + } +} + +const mapDispatchToProps = (dispatch) => { + return { + uiActions: bindActionCreators(uiActions, dispatch), + pusherActions: bindActionCreators(pusherActions, dispatch), + mopidyActions: bindActionCreators(mopidyActions, dispatch), + spotifyActions: bindActionCreators(spotifyActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Debug) \ No newline at end of file diff --git a/src/js/components/Settings/Services.js b/src/js/components/Settings/Services.js new file mode 100755 index 00000000..f7ff49d9 --- /dev/null +++ b/src/js/components/Settings/Services.js @@ -0,0 +1,213 @@ + +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import { Link, hashHistory } from 'react-router' +import { bindActionCreators } from 'redux' +import FontAwesome from 'react-fontawesome' + +import SpotifyAuthenticationFrame from '../SpotifyAuthenticationFrame' +import ConfirmationButton from '../ConfirmationButton' +import PusherConnectionList from '../PusherConnectionList' +import URISchemesList from '../URISchemesList' +import VersionManager from '../VersionManager' +import Header from '../Header' +import Thumbnail from '../Thumbnail' + +import * as uiActions from '../../services/ui/actions' +import * as pusherActions from '../../services/pusher/actions' +import * as mopidyActions from '../../services/mopidy/actions' +import * as spotifyActions from '../../services/spotify/actions' + +class Services extends React.Component{ + + constructor(props) { + super(props) + + this.state = { + spotify_authentication_provider: this.props.spotify.authentication_provider, + spotify_country: this.props.spotify.country, + spotify_locale: this.props.spotify.locale, + input_in_focus: null + } + } + + componentWillReceiveProps(newProps){ + var changed = false + var state = this.state + + if (newProps.spotify.authentication_provider != this.state.spotify_authentication_provider && this.state.input_in_focus != 'spotify_authentication_provider'){ + state.spotify_authentication_provider = newProps.spotify.authentication_provider + changed = true + } + + if (newProps.spotify.country != this.state.spotify_country && this.state.input_in_focus != 'spotify_country'){ + state.spotify_country = newProps.spotify.country + changed = true + } + + if (newProps.spotify.locale != this.state.spotify_locale && this.state.input_in_focus != 'spotify_locale'){ + state.spotify_locale = newProps.spotify.locale + changed = true + } + + if (changed){ + this.setState(state) + } + } + + setSpotifyConfig(state = this.state){ + this.props.spotifyActions.setConfig({ + authentication_provider: state.spotify_authentication_provider, + country: state.spotify_country, + locale: state.spotify_locale + }); + + this.setState({input_in_focus: null}) + } + + setProvider(provider){ + let state = this.state + state.spotify_authentication_provider = provider + this.setSpotifyConfig(state) + this.setState(state) + } + + renderSpotifyUser(){ + + var user = null + if (this.props.spotify.me && this.props.spotify.authorized){ + user = this.props.spotify.me + } else if (this.props.spotify.backend_username && this.props.spotify.backend_username){ + if (this.props.core.users && typeof(this.props.core.users['spotify:user:'+this.props.spotify.backend_username]) !== 'undefined'){ + user = this.props.core.users['spotify:user:'+this.props.spotify.backend_username] + } + } + + if (user){ + return ( + + + + {user.display_name ? user.display_name : user.id} + {!this.props.spotify.authorized ?  (limited access) : null} + + + ) + } else { + return ( + + + + Default user +  (limited access) + + + ) + } + } + + renderSendAuthorizationButton(){ + if( !this.props.spotify.authorized ) return null + + return ( + + ) + } + + render(){ + return ( +
+

Spotify

+
+ +
+ Authentication provider + + +
+
+
Country
+
+ this.setState({ spotify_country: e.target.value })} + onFocus={e => this.setState({input_in_focus: 'spotify_country'})} + onBlur={e => this.setSpotifyConfig() } + value={ this.state.spotify_country } /> +
+
+
+
Locale
+
+ this.setState({ spotify_locale: e.target.value })} + onFocus={e => this.setState({input_in_focus: 'spotify_locale'})} + onBlur={e => this.setSpotifyConfig() } + value={this.state.spotify_locale} /> +
+
+
+
+
Current user
+
+
+ { this.renderSpotifyUser() } +
+
+
+
+
Authentication
+
+ + { this.renderSendAuthorizationButton() } +
+
+
+ ); + } +} + + +/** + * Export our component + * + * We also integrate our global store, using connect() + **/ + +const mapStateToProps = (state, ownProps) => { + return { + spotify: state.spotify + } +} + +const mapDispatchToProps = (dispatch) => { + return { + uiActions: bindActionCreators(uiActions, dispatch), + pusherActions: bindActionCreators(pusherActions, dispatch), + mopidyActions: bindActionCreators(mopidyActions, dispatch), + spotifyActions: bindActionCreators(spotifyActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Services) \ No newline at end of file diff --git a/src/js/components/Settings/System.js b/src/js/components/Settings/System.js new file mode 100755 index 00000000..2cb0b61a --- /dev/null +++ b/src/js/components/Settings/System.js @@ -0,0 +1,194 @@ + +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import { Link, hashHistory } from 'react-router' +import { bindActionCreators } from 'redux' +import FontAwesome from 'react-fontawesome' + +import SpotifyAuthenticationFrame from '../SpotifyAuthenticationFrame' +import ConfirmationButton from '../ConfirmationButton' +import PusherConnectionList from '../PusherConnectionList' +import URISchemesList from '../URISchemesList' +import VersionManager from '../VersionManager' + +import * as uiActions from '../../services/ui/actions' +import * as pusherActions from '../../services/pusher/actions' +import * as mopidyActions from '../../services/mopidy/actions' +import * as spotifyActions from '../../services/spotify/actions' + +class System extends React.Component{ + + constructor(props) { + super(props); + this.state = { + mopidy_host: this.props.mopidy.host, + mopidy_port: this.props.mopidy.port, + pusher_username: this.props.pusher.username, + input_in_focus: null + } + } + + componentWillReceiveProps(newProps){ + var changed = false + var state = this.state + + if (newProps.pusher.username != this.state.pusher_username && this.state.input_in_focus != 'pusher_username'){ + state.pusher_username = newProps.pusher.username + changed = true + } + + if (changed){ + this.setState(state) + } + } + + resetAllSettings(){ + localStorage.clear(); + window.location = '#' + window.location.reload(true) + return false; + } + + setMopidyConfig(e){ + this.setState({input_in_focus: null}) + e.preventDefault(); + this.props.mopidyActions.setConfig({ host: this.state.mopidy_host, port: this.state.mopidy_port }); + window.location.reload(true); + return false; + } + + handleUsernameChange(username){ + this.setState({pusher_username: username.replace(/\W/g, '')}) + } + + handleUsernameBlur(e){ + this.setState({input_in_focus: null}) + this.props.pusherActions.setUsername(this.state.pusher_username) + } + + renderApplyButton(){ + if (this.props.mopidy.host == this.state.mopidy_host && this.props.mopidy.port == this.state.mopidy_port) return null + + return ( +
+
+
+ +
+
+ ) + } + + render(){ + return ( +
+ +

Server

+
this.setMopidyConfig(e)}> +
+
Username
+
+ this.handleUsernameChange(e.target.value)} + onFocus={e => this.setState({input_in_focus: 'pusher_username'})} + onBlur={e => this.handleUsernameBlur(e)} + value={this.state.pusher_username } /> +
+
+
+
Host
+
+ this.setState({ mopidy_host: e.target.value })} + onFocus={e => this.setState({input_in_focus: 'mopidy_host'})} + onBlur={e => this.setState({input_in_focus: null})} + value={ this.state.mopidy_host } /> +
+
+
+
Port
+
+ this.setState({ mopidy_port: e.target.value })} + onFocus={e => this.setState({input_in_focus: 'mopidy_port'})} + onBlur={e => this.setState({input_in_focus: null})} + value={ this.state.mopidy_port } /> +
+
+ {this.renderApplyButton()} +
+ +

Advanced

+ +
+
Customise behavior
+
+ +
+
+ +
+
Connections
+
+ + + +
+
+ +
+
Backends
+
+ + + +
+
+ +
+
System
+
+ this.resetAllSettings()} /> + +
+
+
+ ); + } +} + + +/** + * Export our component + * + * We also integrate our global store, using connect() + **/ + +const mapStateToProps = (state, ownProps) => { + return { + ui: state.ui, + mopidy: state.mopidy, + pusher: state.pusher + } +} + +const mapDispatchToProps = (dispatch) => { + return { + uiActions: bindActionCreators(uiActions, dispatch), + pusherActions: bindActionCreators(pusherActions, dispatch), + mopidyActions: bindActionCreators(mopidyActions, dispatch), + spotifyActions: bindActionCreators(spotifyActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(System) \ No newline at end of file diff --git a/src/js/index.js b/src/js/index.js index 1ca63716..38fc3748 100755 --- a/src/js/index.js +++ b/src/js/index.js @@ -20,7 +20,6 @@ import User from './views/User' import Queue from './views/Queue' import QueueHistory from './views/QueueHistory' import Settings from './views/Settings' -import Debug from './views/Debug' import Search from './views/Search' import DiscoverRecommendations from './views/discover/DiscoverRecommendations' @@ -56,8 +55,7 @@ ReactDOM.render( - - + diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index e5f20591..0ec7d178 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -6,6 +6,7 @@ var uiActions = require('../ui/actions.js') var pusherActions = require('../pusher/actions.js') var mopidyActions = require('../mopidy/actions.js') var spotifyActions = require('../spotify/actions.js') +var lastfmActions = require('../lastfm/actions.js') var helpers = require('../../helpers.js') const CoreMiddleware = (function(){ @@ -20,6 +21,7 @@ const CoreMiddleware = (function(){ case 'CORE_START_SERVICES': store.dispatch(mopidyActions.connect()) store.dispatch(pusherActions.connect()) + store.dispatch(lastfmActions.connect()) if (store.getState().spotify.enabled){ store.dispatch(spotifyActions.connect()) diff --git a/src/js/services/lastfm/actions.js b/src/js/services/lastfm/actions.js index 4f3425dd..58d6a36a 100755 --- a/src/js/services/lastfm/actions.js +++ b/src/js/services/lastfm/actions.js @@ -35,6 +35,20 @@ const sendRequest = ( dispatch, getState, params ) => { }) } +export function connect(){ + return (dispatch, getState) => { + + dispatch({ type: 'LASTFM_CONNECTING' }) + + sendRequest(dispatch, getState, 'method=artist.getInfo&artist=') + .then( + response => { + dispatch({ type: 'LASTFM_CONNECTED' }) + } + ) + } +} + export function getArtist( uri, artist, mbid = false ){ return (dispatch, getState) => { if( mbid ){ diff --git a/src/js/services/lastfm/reducer.js b/src/js/services/lastfm/reducer.js index 3af57052..226d4bb3 100755 --- a/src/js/services/lastfm/reducer.js +++ b/src/js/services/lastfm/reducer.js @@ -2,6 +2,13 @@ export default function reducer(lastfm = {}, action){ switch (action.type) { + case 'LASTFM_CONNECT': + case 'LASTFM_CONNECTING': + return Object.assign({}, lastfm, { connected: false, connecting: true }); + + case 'LASTFM_CONNECTED': + return Object.assign({}, lastfm, { connected: true, connecting: false }); + default: return lastfm } diff --git a/src/js/services/localstorage/middleware.js b/src/js/services/localstorage/middleware.js index 7a58a988..be21cd1c 100755 --- a/src/js/services/localstorage/middleware.js +++ b/src/js/services/localstorage/middleware.js @@ -73,6 +73,7 @@ const localstorageMiddleware = (function(){ if( !spotify ) spotify = {}; Object.assign( spotify,{ + authentication_provider: action.config.authentication_provider, country: action.config.country, locale: action.config.locale } diff --git a/src/js/services/pusher/middleware.js b/src/js/services/pusher/middleware.js index 02c9a043..0fbc278f 100755 --- a/src/js/services/pusher/middleware.js +++ b/src/js/services/pusher/middleware.js @@ -328,6 +328,16 @@ const PusherMiddleware = (function(){ next( action ) break + case 'PUSHER_CONFIG': + store.dispatch(spotifyActions.setConfig({ + locale: (action.config.locale ? action.config.locale : null), + country: (action.config.country ? action.config.country : null), + authorization_url: (action.config.authorization_url ? action.config.authorization_url : null), + backend_username: (action.config.backend_username ? action.config.backend_username : null) + })) + next( action ) + break + case 'PUSHER_DEBUG': request(store, action.message.method, action.message.data ) .then( diff --git a/src/js/views/Debug.js b/src/js/views/Debug.js deleted file mode 100755 index d6998416..00000000 --- a/src/js/views/Debug.js +++ /dev/null @@ -1,228 +0,0 @@ - -import React, { PropTypes } from 'react' -import { connect } from 'react-redux' -import { Link, hashHistory } from 'react-router' -import { bindActionCreators } from 'redux' -import FontAwesome from 'react-fontawesome' - -import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame' -import ConfirmationButton from '../components/ConfirmationButton' -import PusherConnectionList from '../components/PusherConnectionList' -import URISchemesList from '../components/URISchemesList' -import VersionManager from '../components/VersionManager' -import Header from '../components/Header' -import Thumbnail from '../components/Thumbnail' - -import * as uiActions from '../services/ui/actions' -import * as pusherActions from '../services/pusher/actions' -import * as mopidyActions from '../services/mopidy/actions' -import * as spotifyActions from '../services/spotify/actions' - -class Debug extends React.Component{ - - constructor(props) { - super(props); - this.state = { - mopidy_call: 'playlists.asList', - mopidy_data: '{}', - pusher_data: '{"method":"get_config"}', - access_token: this.props.access_token - } - } - - callMopidy(e){ - e.preventDefault() - this.props.mopidyActions.debug( this.state.mopidy_call, JSON.parse(this.state.mopidy_data) ) - } - - callPusher(e){ - e.preventDefault() - this.props.pusherActions.debug( JSON.parse(this.state.pusher_data) ) - } - - render(){ - - var options = ( - - - - ) - - return ( -
-
- -
- -

User interface

-
-
-
Debug
-
- -
-
-
-
Logging
-
- - - -
-
- -
- -

Spotify

-
-
Access token
-
- this.props.spotifyActions.authorizationGranted({access_token: e.target.value})} - value={this.state.access_token} /> -
-
- -

Mopidy

-
this.callMopidy(e)}> -
-
Call
-
- this.setState({ mopidy_call: e.target.value })} - value={ this.state.mopidy_call } /> -
-
-
-
Data
-
- -
-
-
-
-
- -
-
-
- -

Pusher

-
this.callPusher(e)}> -
-
Examples
-
- -
-
-
-
Data
-
- -
-
-
-
-
- -
-
-
- -

Response

-
-						{ this.props.debug_response ? JSON.stringify(this.props.debug_response, null, 2) : null }
-					
- -
-
- ); - } -} - - -/** - * Export our component - * - * We also integrate our global store, using connect() - **/ - -const mapStateToProps = (state, ownProps) => { - return { - connection_id: state.pusher.connection_id, - access_token: (state.spotify.access_token ? state.spotify.access_token : ''), - log_actions: (state.ui.log_actions ? state.ui.log_actions : false), - log_pusher: (state.ui.log_pusher ? state.ui.log_pusher : false), - log_mopidy: (state.ui.log_mopidy ? state.ui.log_mopidy : false), - debug_info: (state.ui.debug_info ? state.ui.debug_info : false), - debug_response: state.ui.debug_response - } -} - -const mapDispatchToProps = (dispatch) => { - return { - uiActions: bindActionCreators(uiActions, dispatch), - pusherActions: bindActionCreators(pusherActions, dispatch), - mopidyActions: bindActionCreators(mopidyActions, dispatch), - spotifyActions: bindActionCreators(spotifyActions, dispatch) - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(Debug) \ No newline at end of file diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js index 4e663d1d..e0789451 100755 --- a/src/js/views/Settings.js +++ b/src/js/views/Settings.js @@ -1,389 +1,92 @@ import React, { PropTypes } from 'react' -import { connect } from 'react-redux' -import { hashHistory, Link } from 'react-router' -import { bindActionCreators } from 'redux' import FontAwesome from 'react-fontawesome' +import { Link } from 'react-router' -import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame' -import ConfirmationButton from '../components/ConfirmationButton' -import PusherConnectionList from '../components/PusherConnectionList' -import URISchemesList from '../components/URISchemesList' -import VersionManager from '../components/VersionManager' import Header from '../components/Header' -import Icon from '../components/Icon' -import Thumbnail from '../components/Thumbnail' +import System from '../components/Settings/System' +import Services from '../components/Settings/Services' +import Debug from '../components/Settings/Debug' -import * as uiActions from '../services/ui/actions' -import * as pusherActions from '../services/pusher/actions' -import * as mopidyActions from '../services/mopidy/actions' -import * as spotifyActions from '../services/spotify/actions' - -class Settings extends React.Component{ - - constructor(props) { - super(props); - this.state = { - mopidy_host: this.props.mopidy.host, - mopidy_port: this.props.mopidy.port, - spotify_country: this.props.spotify.country, - spotify_locale: this.props.spotify.locale, - pusher_username: this.props.pusher.username, - input_in_focus: null - } - } - - componentWillReceiveProps(newProps){ - var changed = false - var state = this.state - - if (newProps.spotify.country != this.state.spotify_country && this.state.input_in_focus != 'spotify_country'){ - state.spotify_country = newProps.spotify.country - changed = true - } - - if (newProps.spotify.locale != this.state.spotify_locale && this.state.input_in_focus != 'spotify_locale'){ - state.spotify_locale = newProps.spotify.locale - changed = true - } - - if (newProps.pusher.username != this.state.pusher_username && this.state.input_in_focus != 'pusher_username'){ - state.pusher_username = newProps.pusher.username - changed = true - } - - if (changed){ - this.setState(state) - } - } - - resetAllSettings(){ - localStorage.clear(); - window.location = '#' - window.location.reload(true) - return false; - } - - setMopidyConfig(e){ - this.setState({input_in_focus: null}) - e.preventDefault(); - this.props.mopidyActions.setConfig({ host: this.state.mopidy_host, port: this.state.mopidy_port }); - window.location.reload(true); - return false; - } - - setSpotifyConfig(e){ - this.setState({input_in_focus: null}) - e.preventDefault(); - this.props.spotifyActions.setConfig({ country: this.state.spotify_country, locale: this.state.spotify_locale }); - return false; - } - - handleUsernameChange(username){ - this.setState({pusher_username: username.replace(/\W/g, '')}) - } - - handleUsernameBlur(e){ - this.setState({input_in_focus: null}) - this.props.pusherActions.setUsername(this.state.pusher_username) - } - - renderSpotifyUser(){ - - 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 ( - - - - {user.display_name ? user.display_name : user.id} - {!this.props.spotify.authorized ?  (limited access) : null} - - - ) - } else { - return ( - - - - Default user -  (limited access) - - - ) - } - } - - renderSendAuthorizationButton(){ - if( !this.props.spotify.authorized ) return null +export default class Settings extends React.Component { + renderSubViewMenu(){ return ( - - ) - } - - renderApplyButton(){ - if (this.props.mopidy.host == this.state.mopidy_host && this.props.mopidy.port == this.state.mopidy_port) return null - - return ( -
-
-
- -
+
+

System

+

Services

+

Debug

+

About

) } - serviceStatus(service){ + renderSubView(){ + switch (this.props.params.sub_view){ - var icon = null - var status = 'Unknown' + case 'services': + return ( +
+ +
+ ) - if (this.props[service].enabled !== undefined && !this.props[service].enabled){ - icon = - status = 'disabled' - } else if (this.props[service].connecting){ - icon = - status = 'connecting' - } else if (this.props[service].connected){ - icon = - status = 'connected' - } else { - icon = - status = 'disconnected' + case 'debug': + return ( +
+ +
+ ) + + case 'about': + return ( +
+
+
+ Iris is an open-source project by James Barnsley. It is provided free and with absolutely no warranty. If you paid someone for this software, please let me know. +
+
+ Google Analytics is used to help trace issues and provide valuable insight into how we can continue to make improvements. +
+
+

+
+ +  Donate + +    + +  GitHub + +    + Creative Commons License +
+
+
+ ) + + default: + return ( +
+ +
+ ) } - - return ( -
- -

{service}

-
{icon}  {status}
-
-
- ) } render(){ - - var options = ( - - - -   - Help - - - ) - return (
-
+
-
- {this.serviceStatus('mopidy')} - {this.serviceStatus('pusher')} - {this.serviceStatus('spotify')} -
- -

System

-
this.setMopidyConfig(e)}> -
-
Username
-
- this.handleUsernameChange(e.target.value)} - onFocus={e => this.setState({input_in_focus: 'pusher_username'})} - onBlur={e => this.handleUsernameBlur(e)} - value={this.state.pusher_username } /> -
-
-
-
Host
-
- this.setState({ mopidy_host: e.target.value })} - onFocus={e => this.setState({input_in_focus: 'mopidy_host'})} - onBlur={e => this.setState({input_in_focus: null})} - value={ this.state.mopidy_host } /> -
-
-
-
Port
-
- this.setState({ mopidy_port: e.target.value })} - onFocus={e => this.setState({input_in_focus: 'mopidy_port'})} - onBlur={e => this.setState({input_in_focus: null})} - value={ this.state.mopidy_port } /> -
-
- {this.renderApplyButton()} -
- -

Spotify

-
-
-
- -
-
-
-
Country
-
- this.setState({ spotify_country: e.target.value })} - onFocus={e => this.setState({input_in_focus: 'spotify_country'})} - onBlur={e => this.setSpotifyConfig(e) } - value={ this.state.spotify_country } /> -
-
-
-
Locale
-
- this.setState({ spotify_locale: e.target.value })} - onFocus={e => this.setState({input_in_focus: 'spotify_locale'})} - onBlur={e => this.setSpotifyConfig(e) } - value={this.state.spotify_locale} /> -
-
-
-
-
Current user
-
-
- { this.renderSpotifyUser() } -
-
-
-
-
Authentication
-
- - { this.renderSendAuthorizationButton() } -
-
- -

Advanced

- -
-
Customise behavior
-
- -
-
- -
-
Connections
-
- - - -
-
- -
-
Backends
-
- - - -
-
- -
-
System
-
- this.resetAllSettings()} /> - -
-
- -

About

- -
-
- Iris is an open-source project by James Barnsley. It is provided free and with absolutely no warranty. If you paid someone for this software, please let me know. -
-
- Google Analytics is used to help trace issues and provide valuable insight into how we can continue to make improvements. -
-
-

-
- -  Donate - -    - -  GitHub - -    - Creative Commons License -
-
+ {this.renderSubViewMenu()} + {this.renderSubView()}
); } -} - - -/** - * Export our component - * - * We also integrate our global store, using connect() - **/ - -const mapStateToProps = (state, ownProps) => { - return state; -} - -const mapDispatchToProps = (dispatch) => { - return { - uiActions: bindActionCreators(uiActions, dispatch), - pusherActions: bindActionCreators(pusherActions, dispatch), - mopidyActions: bindActionCreators(mopidyActions, dispatch), - spotifyActions: bindActionCreators(spotifyActions, dispatch) - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(Settings) \ No newline at end of file +} \ No newline at end of file diff --git a/src/scss/app.scss b/src/scss/app.scss index 54d34989..93cb1750 100755 --- a/src/scss/app.scss +++ b/src/scss/app.scss @@ -23,6 +23,7 @@ @import 'components/notifications'; @import 'components/dropdown-field'; @import 'components/autocomplete-field'; +@import 'components/sub-views'; @import 'components/debug'; @import 'views/artist'; diff --git a/src/scss/components/_sub-views.scss b/src/scss/components/_sub-views.scss new file mode 100755 index 00000000..10a8d264 --- /dev/null +++ b/src/scss/components/_sub-views.scss @@ -0,0 +1,26 @@ + + +.sub-views { + .option { + @include feature_font(); + color: $white; + display: inline-block; + margin-right: 25px; + font-size: 15px; + font-weight: 500; + border-bottom: 3px solid transparent; + cursor: pointer; + + h4 { + margin: 8px 0 4px; + } + + &.active { + border-color: $white; + } + + &:not(.active):hover { + border-color: rgba(255,255,255,0.2); + } + } +} \ No newline at end of file diff --git a/src/scss/global/_forms.scss b/src/scss/global/_forms.scss index 4a47af81..6699bc06 100755 --- a/src/scss/global/_forms.scss +++ b/src/scss/global/_forms.scss @@ -194,7 +194,7 @@ input[type="submit"] { .name { display: block; padding-top: 10px; - width: 15%; + width: 20%; float: left; } @@ -208,7 +208,7 @@ input[type="submit"] { } .input { - width: 85%; + width: 80%; float: left; input, diff --git a/src/scss/views/_artist.scss b/src/scss/views/_artist.scss index afc6aa21..b470695e 100755 --- a/src/scss/views/_artist.scss +++ b/src/scss/views/_artist.scss @@ -37,31 +37,6 @@ color: $white; } } - - .sub-views { - .option { - @include feature_font(); - color: $white; - display: inline-block; - margin-right: 25px; - font-size: 15px; - font-weight: 500; - border-bottom: 3px solid transparent; - cursor: pointer; - - h4 { - margin: 8px 0 4px; - } - - &.active { - border-color: $white; - } - - &:not(.active):hover { - border-color: rgba(255,255,255,0.2); - } - } - } } } diff --git a/src/scss/views/_settings.scss b/src/scss/views/_settings.scss index b1cfe36e..283b4fa0 100755 --- a/src/scss/views/_settings.scss +++ b/src/scss/views/_settings.scss @@ -1,6 +1,10 @@ .settings-view { + .sub-views { + padding-bottom: 40px; + } + .services { @include clearfix(); @@ -8,7 +12,7 @@ background: lighten($dark_grey,2%); padding: 12px 15px; width: 24%; - margin-right: 2%; + margin-right: 1.3334%; float: left; border-radius: 3px; box-sizing: border-box; @@ -27,13 +31,15 @@ } } - &.connected { + &.connected, + &.available { .status { color: $green; } } - &.disconnected { + &.disconnected, + &.unavailable { .status { color: $red; }