Service tiles; Start handling disabled services
This commit is contained in:
@ -50,13 +50,6 @@ class App extends React.Component{
|
||||
this.props.coreActions.startServices()
|
||||
this.props.coreActions.getBroadcasts()
|
||||
|
||||
if (this.props.spotify_authorized){
|
||||
|
||||
// TODO: remove this so we don't tap out our API limits before we even get started
|
||||
// Perhaps fire this on demand? Context menu, playlists loading or AddToPlaylistModal
|
||||
this.props.spotifyActions.getAllLibraryPlaylists();
|
||||
}
|
||||
|
||||
// when we navigate to a new route
|
||||
hashHistory.listen( location => {
|
||||
|
||||
|
||||
1
src/js/bootstrap.js
vendored
1
src/js/bootstrap.js
vendored
@ -60,6 +60,7 @@ var initialState = {
|
||||
track: {}
|
||||
},
|
||||
spotify: {
|
||||
enabled: true,
|
||||
connected: false,
|
||||
me: false,
|
||||
autocomplete_results: {},
|
||||
|
||||
@ -90,7 +90,7 @@ class Sidebar extends React.Component{
|
||||
<Link className={this.linkClassName('settings')} to={global.baseURL+"settings"}>
|
||||
<Icon name="cog" />
|
||||
Settings
|
||||
{ !this.props.mopidy_connected || !this.props.spotify_connected || !this.props.pusher_connected ? <FontAwesome name="exclamation-triangle" className="red-text pull-right" /> : null }
|
||||
{ !this.props.mopidy_connected || (!this.props.spotify_connected && this.props.spotify_enabled) || !this.props.pusher_connected ? <FontAwesome name="exclamation-triangle" className="red-text pull-right" /> : null }
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
@ -115,6 +115,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
pusher_connected: state.pusher.connected,
|
||||
spotify_enabled: state.spotify.enabled,
|
||||
spotify_connected: state.spotify.connected,
|
||||
spotify_authorized: state.spotify.authorized,
|
||||
dragger: state.ui.dragger
|
||||
|
||||
@ -20,7 +20,11 @@ const CoreMiddleware = (function(){
|
||||
case 'CORE_START_SERVICES':
|
||||
store.dispatch(mopidyActions.connect())
|
||||
store.dispatch(pusherActions.connect())
|
||||
store.dispatch(spotifyActions.connect())
|
||||
|
||||
if (store.getState().spotify.enabled){
|
||||
store.dispatch(spotifyActions.connect())
|
||||
}
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
case 'MOPIDY_URISCHEMES':
|
||||
var uri_schemes = action.data
|
||||
var remove = ['http','https','mms','rtmp','rtmps','rtsp','sc','spotify']
|
||||
var remove = ['http','https','mms','rtmp','rtmps','rtsp','sc']
|
||||
|
||||
// remove all our ignored types
|
||||
for( var i = 0; i < remove.length; i++ ){
|
||||
@ -279,10 +279,12 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
// it's a spotify playlist that we haven't loaded
|
||||
// we need to fetch via HTTP API to avoid timeout
|
||||
} else if (helpers.uriSource(action.uri) == 'spotify'){
|
||||
} else if (helpers.uriSource(action.uri) == 'spotify' && store.getState().spotify.enabled){
|
||||
store.dispatch(uiActions.startProcess('MOPIDY_ENQUEUE_URIS', 'Fetching tracks'))
|
||||
store.dispatch(spotifyActions.getAllPlaylistTracks(action.uri))
|
||||
break
|
||||
|
||||
// Not in index, and Spotify HTTP not enabled, so just play it as-is
|
||||
}
|
||||
|
||||
// fetch the playlist tracks via backend
|
||||
|
||||
@ -109,7 +109,7 @@ const PusherMiddleware = (function(){
|
||||
|
||||
response.type = 'PUSHER_CONFIG'
|
||||
store.dispatch(response)
|
||||
if (response.config.spotify_username){
|
||||
if (response.config.spotify_username && store.getState().spotify.enabled){
|
||||
store.dispatch(spotifyActions.getUser('spotify:user:'+response.config.spotify_username))
|
||||
}
|
||||
var spotify = store.getState().spotify
|
||||
@ -303,7 +303,7 @@ const PusherMiddleware = (function(){
|
||||
|
||||
case 'PUSHER_RADIO_STARTED':
|
||||
case 'PUSHER_RADIO_CHANGED':
|
||||
if (action.radio.enabled){
|
||||
if (action.radio.enabled && store.getState().spotify.enabled){
|
||||
store.dispatch(spotifyActions.resolveRadioSeeds(action.radio))
|
||||
}
|
||||
next(action)
|
||||
|
||||
@ -171,11 +171,6 @@ function refreshToken( dispatch, getState ){
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export function setConfig( config ){
|
||||
return {
|
||||
type: 'SPOTIFY_SET_CONFIG',
|
||||
|
||||
@ -16,10 +16,21 @@ const SpotifyMiddleware = (function(){
|
||||
|
||||
switch(action.type){
|
||||
|
||||
case 'SPOTIFY_CONNECT':
|
||||
store.dispatch( spotifyActions.getMe() )
|
||||
break
|
||||
|
||||
case 'SPOTIFY_CONNECTED':
|
||||
var label = null
|
||||
if (store.getState().spotify.me) label = store.getState().spotify.me.id
|
||||
ReactGA.event({ category: 'Spotify', action: 'Connected', label: label })
|
||||
|
||||
// TODO: remove this so we don't tap out our API limits before we even get started
|
||||
// Perhaps fire this on demand? Context menu, playlists loading or AddToPlaylistModal
|
||||
if (store.getState().spotify_authorized){
|
||||
store.dispatch(spotifyActions.getAllLibraryPlaylists())
|
||||
}
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
@ -56,10 +67,6 @@ const SpotifyMiddleware = (function(){
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'SPOTIFY_CONNECT':
|
||||
store.dispatch( spotifyActions.getMe() )
|
||||
break
|
||||
|
||||
case 'SPOTIFY_CREATE_PLAYLIST':
|
||||
if( !store.getState().spotify.authorized ){
|
||||
store.dispatch( uiActions.createNotification( "Must be logged in to Spotify to do that", 'bad' ) )
|
||||
|
||||
@ -3,7 +3,6 @@ import ReactGA from 'react-ga'
|
||||
|
||||
var uiActions = require('./actions.js')
|
||||
var mopidyActions = require('../mopidy/actions.js')
|
||||
var spotifyActions = require('../spotify/actions.js')
|
||||
var helpers = require('../../helpers.js')
|
||||
|
||||
const UIMiddleware = (function(){
|
||||
|
||||
@ -141,12 +141,12 @@ class Artist extends React.Component{
|
||||
return (
|
||||
<div className="body about">
|
||||
|
||||
<div className="col w40 tiles">
|
||||
<div className="col w40 tiles artist-stats">
|
||||
{this.props.artist.images ? <div className="tile thumbnail-wrapper"><Thumbnail size="huge" canZoom images={this.props.artist.images} /></div> : null}
|
||||
{this.props.artist.images_additional ? <div className="tile thumbnail-wrapper"><Thumbnail size="huge" canZoom images={this.props.artist.images_additional} /></div> : null}
|
||||
{this.props.artist.followers ? <div className="tile"><span className="text"><FontAwesome name="users" />{this.props.artist.followers.total.toLocaleString() } followers</span></div> : null}
|
||||
{this.props.artist.popularity ? <div className="tile"><span className="text"><FontAwesome name="fire" />{this.props.artist.popularity }% popularity</span></div> : null}
|
||||
{this.props.artist.listeners ? <div className="tile"><span className="text"><FontAwesome name="headphones" />{ this.props.artist.listeners.toLocaleString() } listeners</span></div> : null }
|
||||
{this.props.artist.followers ? <div className="tile"><span className="content"><FontAwesome name="users" />{this.props.artist.followers.total.toLocaleString() } followers</span></div> : null}
|
||||
{this.props.artist.popularity ? <div className="tile"><span className="content"><FontAwesome name="fire" />{this.props.artist.popularity }% popularity</span></div> : null}
|
||||
{this.props.artist.listeners ? <div className="tile"><span className="content"><FontAwesome name="headphones" />{ this.props.artist.listeners.toLocaleString() } listeners</span></div> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w60 biography">
|
||||
|
||||
@ -88,42 +88,6 @@ class Settings extends React.Component{
|
||||
this.props.pusherActions.setUsername(this.state.pusher_username)
|
||||
}
|
||||
|
||||
renderConnectionStatus(service){
|
||||
if (service == 'Spotify' && !this.props[service.toLowerCase()].authorized){
|
||||
return (
|
||||
<span className="red-text connection-status">
|
||||
<FontAwesome name="exclamation-triangle" />
|
||||
|
||||
Not connected
|
||||
</span>
|
||||
)
|
||||
} else if (this.props[service.toLowerCase()].connected){
|
||||
return (
|
||||
<span className="green-text connection-status">
|
||||
<FontAwesome name="check" />
|
||||
|
||||
{service}
|
||||
</span>
|
||||
)
|
||||
} else if (this.props[service.toLowerCase()].connecting){
|
||||
return (
|
||||
<span className="grey-text connection-status">
|
||||
<FontAwesome name="circle-o-notch" spin />
|
||||
|
||||
Connecting
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="red-text connection-status">
|
||||
<FontAwesome name="exclamation-triangle" />
|
||||
|
||||
Not connected
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderSpotifyUser(){
|
||||
|
||||
var user = null
|
||||
@ -186,25 +150,26 @@ class Settings extends React.Component{
|
||||
var icon = null
|
||||
var status = 'Unknown'
|
||||
|
||||
if (this.props[service].connecting){
|
||||
icon = <span className="icon connecting"><FontAwesome name="plug" /></span>
|
||||
status = 'Connecting'
|
||||
} else if (service == 'spotify' && !this.props[service].authorized){
|
||||
icon = <span className="icon warning"><FontAwesome name="check" /></span>
|
||||
status = 'Connected (not authorized)'
|
||||
if (this.props[service].enabled !== undefined && !this.props[service].enabled){
|
||||
icon = <span className="icon"><FontAwesome fixedWidth name="power-off" /></span>
|
||||
status = 'disabled'
|
||||
} else if (this.props[service].connecting){
|
||||
icon = <span className="icon"><FontAwesome fixedWidth name="plug" /></span>
|
||||
status = 'connecting'
|
||||
} else if (this.props[service].connected){
|
||||
icon = <span className="icon connected"><FontAwesome name="check" /></span>
|
||||
status = 'Connected'
|
||||
icon = <span className="icon"><FontAwesome fixedWidth name="check" /></span>
|
||||
status = 'connected'
|
||||
} else {
|
||||
icon = <span className="icon disconnected"><FontAwesome name="close" /></span>
|
||||
status = 'Disconnected'
|
||||
icon = <span className="icon disconnected"><FontAwesome fixedWidth name="close" /></span>
|
||||
status = 'disconnected'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="service">
|
||||
<h4>{service}</h4>
|
||||
{icon}
|
||||
<span className="text">{status}</span>
|
||||
<div className={'service '+status}>
|
||||
<span className="content">
|
||||
<h4 className="title">{service}</h4>
|
||||
<div className="status">{icon} {status}</div>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -276,6 +241,19 @@ class Settings extends React.Component{
|
||||
|
||||
<h4 className="underline">Spotify</h4>
|
||||
<form>
|
||||
<div className="field checkbox">
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="spotify_enabled"
|
||||
checked={ this.props.spotify.enabled }
|
||||
onChange={e => this.props.spotifyActions.setConfig({enabled: !this.props.spotify.enabled})}
|
||||
/>
|
||||
<span className="label">Enabled</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">Country</div>
|
||||
<div className="input">
|
||||
|
||||
@ -137,4 +137,93 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tiles {
|
||||
padding-bottom: 60px;
|
||||
|
||||
.tile {
|
||||
color: $white;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
vertical-align: top;
|
||||
margin-top: -12px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include clearfix();
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
background: lighten($dark_grey,2%);
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
&.thumbnail-wrapper {
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.artist-stats {
|
||||
|
||||
.tile {
|
||||
.fa {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
text-align: center;
|
||||
margin-top: -27px;
|
||||
font-size: 60px;
|
||||
z-index: -1;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( null, $bp_medium ){
|
||||
.tile {
|
||||
@include grid_item( 2 );
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_medium ){
|
||||
padding-bottom: 20px;
|
||||
|
||||
.tile {
|
||||
@include grid_item( 3 );
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_narrow ){
|
||||
.tile {
|
||||
.text {
|
||||
font-size: 14px;
|
||||
.fa {
|
||||
font-size: 28px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,82 +84,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tiles {
|
||||
padding-bottom: 60px;
|
||||
|
||||
.tile {
|
||||
color: $white;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
|
||||
.text {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
vertical-align: top;
|
||||
margin-top: -12px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
|
||||
.fa {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
text-align: center;
|
||||
margin-top: -27px;
|
||||
font-size: 60px;
|
||||
z-index: -1;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
background: lighten($dark_grey,2%);
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
&.thumbnail-wrapper {
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( null, $bp_medium ){
|
||||
.tile {
|
||||
@include grid_item( 2 );
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_medium ){
|
||||
padding-bottom: 20px;
|
||||
|
||||
.tile {
|
||||
@include grid_item( 3 );
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_narrow ){
|
||||
.tile {
|
||||
.text {
|
||||
font-size: 14px;
|
||||
.fa {
|
||||
font-size: 28px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,11 +47,16 @@
|
||||
background: $green;
|
||||
}
|
||||
|
||||
&.broadcast {
|
||||
&.broadcast,
|
||||
&.info {
|
||||
background: $yellow;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: $orange;
|
||||
}
|
||||
|
||||
&.bad {
|
||||
background: $red;
|
||||
}
|
||||
|
||||
@ -1,53 +1,56 @@
|
||||
|
||||
.settings-view {
|
||||
|
||||
.services {
|
||||
@include clearfix();
|
||||
|
||||
.service {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 0 0 0 45px;
|
||||
margin: 0 20px 10px 0;
|
||||
min-width: 80px;
|
||||
background: lighten($dark_grey,2%);
|
||||
padding: 12px 15px;
|
||||
width: 24%;
|
||||
margin-right: 2%;
|
||||
float: left;
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
|
||||
h4 {
|
||||
padding: 0;
|
||||
margin: 0 0 -3px 0;
|
||||
&:nth-child(4n){
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $grey;
|
||||
}
|
||||
|
||||
&.connecting {
|
||||
.status {
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
&.connected {
|
||||
.status {
|
||||
color: $green;
|
||||
}
|
||||
}
|
||||
|
||||
&.disconnected {
|
||||
.status {
|
||||
color: $red;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
text-transform: capitalize;
|
||||
margin: 2px 0 5px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 35px;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
border-radius: 50%;
|
||||
color: $white;
|
||||
text-align: center;
|
||||
padding-top: 10px;
|
||||
|
||||
&.connecting {
|
||||
background: $mid_grey;
|
||||
}
|
||||
|
||||
&.connected {
|
||||
background: $green;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: $orange;
|
||||
}
|
||||
|
||||
&.disconnected {
|
||||
background: $red;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
|
||||
.status {
|
||||
text-transform: capitalize;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.field.current-user {
|
||||
.text {
|
||||
padding: 14px 14px 14px 0px;
|
||||
|
||||
Reference in New Issue
Block a user