2016-10-17 10:39:11 +13:00
import React , { PropTypes } from 'react'
2017-08-05 22:25:25 +12:00
import { connect } from 'react-redux'
import { hashHistory , Link } from 'react-router'
import { bindActionCreators } from 'redux'
2016-10-17 10:39:11 +13:00
import FontAwesome from 'react-fontawesome'
2016-11-29 15:36:01 +13:00
2017-08-05 22:25:25 +12:00
import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame'
2017-11-02 21:20:56 +13:00
import LastfmAuthenticationFrame from '../components/LastfmAuthenticationFrame'
2017-08-05 22:25:25 +12:00
import ConfirmationButton from '../components/ConfirmationButton'
import PusherConnectionList from '../components/PusherConnectionList'
import URISchemesList from '../components/URISchemesList'
import VersionManager from '../components/VersionManager'
2016-10-23 23:48:06 +13:00
import Header from '../components/Header'
2017-08-04 16:08:57 +12:00
import Parallax from '../components/Parallax'
2017-08-05 22:25:25 +12:00
import Icon from '../components/Icon'
import Thumbnail from '../components/Thumbnail'
2017-11-03 09:06:41 +13:00
import URILink from '../components/URILink'
2016-10-17 10:39:11 +13:00
2017-08-05 22:25:25 +12:00
import * as coreActions from '../services/core/actions'
import * as uiActions from '../services/ui/actions'
import * as pusherActions from '../services/pusher/actions'
import * as mopidyActions from '../services/mopidy/actions'
2017-11-03 09:06:41 +13:00
import * as lastfmActions from '../services/lastfm/actions'
2017-08-05 22:25:25 +12:00
import * as spotifyActions from '../services/spotify/actions'
class Settings extends React . Component {
2017-10-10 13:05:28 +13:00
constructor ( props ) {
2017-08-05 22:25:25 +12:00
super ( props ) ;
this . state = {
country : this . props . core . country ,
locale : this . props . core . locale ,
mopidy _host : this . props . mopidy . host ,
mopidy _port : this . props . mopidy . port ,
2017-11-27 16:38:33 +13:00
mopidy _ssl : this . props . mopidy . ssl ,
2017-08-05 22:25:25 +12:00
pusher _username : this . props . pusher . username ,
input _in _focus : null
}
}
2017-11-13 16:52:53 +13:00
componentDidMount ( ) {
if ( this . props . lastfm . session && this . props . core . users [ "lastfm:user:" + this . props . lastfm . session . name ] === undefined ) {
this . props . lastfmActions . getMe ( ) ;
}
}
2017-08-05 22:25:25 +12:00
componentWillReceiveProps ( newProps ) {
var changed = false
var state = this . state
2017-09-26 20:49:17 +13:00
if ( newProps . core . country != this . state . country && this . state . input _in _focus != 'country' ) {
state . country = newProps . core . country
2017-08-05 22:25:25 +12:00
changed = true
}
2017-09-26 20:49:17 +13:00
if ( newProps . core . locale != this . state . locale && this . state . input _in _focus != 'locale' ) {
state . locale = newProps . core . locale
2017-08-05 22:25:25 +12:00
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 ;
}
2017-11-27 16:38:33 +13:00
setConfig ( e ) {
this . setState ( { input _in _focus : null } ) ;
2017-08-05 22:25:25 +12:00
e . preventDefault ( ) ;
2017-11-27 16:38:33 +13:00
this . props . mopidyActions . setConfig ( {
host : this . state . mopidy _host ,
port : this . state . mopidy _port ,
ssl : this . state . mopidy _ssl
} ) ;
2017-08-05 22:25:25 +12:00
window . location . reload ( true ) ;
return false ;
}
handleBlur ( name , value ) {
this . setState ( { input _in _focus : null } )
var data = { }
data [ name ] = value
this . props . coreActions . set ( data )
}
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 ( ) {
2017-11-27 16:38:33 +13:00
if ( this . props . mopidy . host == this . state . mopidy _host &&
this . props . mopidy . port == this . state . mopidy _port &&
this . props . mopidy . ssl == this . state . mopidy _ssl ) {
return null ;
}
2017-06-27 09:07:25 +12:00
return (
2017-08-05 22:25:25 +12:00
< div className = "field" >
< div className = "name" > < / d i v >
< div className = "input" >
< button type = "submit" className = "secondary" > Apply and reload < / b u t t o n >
< / d i v >
2017-06-27 09:07:25 +12:00
< / d i v >
)
2017-02-21 08:35:24 +13:00
}
2017-08-05 22:25:25 +12:00
renderSpotifyUser ( ) {
2017-11-13 16:52:53 +13:00
var user = this . props . spotify . me ;
2017-02-21 08:35:24 +13:00
2017-08-05 22:25:25 +12:00
if ( user ) {
return (
2017-11-03 09:06:41 +13:00
< URILink className = "user" type = "user" uri = { user . uri } >
2017-08-05 22:25:25 +12:00
< Thumbnail circle = { true } size = "small" images = { user . images } / >
< span className = "user-name" >
{ user . display _name ? user . display _name : user . id }
2017-11-04 14:03:59 +13:00
{ ! this . props . spotify . authorization ? < span className = "grey-text" > & nbsp ; & nbsp ; ( Limited access ) < / s p a n > : n u l l }
2017-08-05 22:25:25 +12:00
< / s p a n >
2017-11-03 09:06:41 +13:00
< / U R I L i n k >
2017-08-05 22:25:25 +12:00
)
} else {
return (
2017-11-03 09:06:41 +13:00
< URILink className = "user" >
2017-08-05 22:25:25 +12:00
< Thumbnail circle = { true } size = "small" / >
< span className = "user-name" >
Unknown
< / s p a n >
2017-11-03 09:06:41 +13:00
< / U R I L i n k >
)
}
}
renderLastfmUser ( ) {
var user = this . props . core . users [ "lastfm:user:" + this . props . lastfm . session . name ] ;
if ( user ) {
return (
2017-11-17 08:43:22 +13:00
< span className = "user" >
2017-11-03 09:06:41 +13:00
< Thumbnail circle = { true } size = "small" images = { user . image } / >
< span className = "user-name" >
{ user . realname ? user . realname : user . name }
< / s p a n >
2017-11-17 08:43:22 +13:00
< / s p a n >
2017-11-03 09:06:41 +13:00
)
} else {
return (
2017-11-17 08:43:22 +13:00
< span className = "user" >
2017-11-03 09:06:41 +13:00
< Thumbnail circle = { true } size = "small" / >
< span className = "user-name" >
Unknown
< / s p a n >
2017-11-17 08:43:22 +13:00
< / s p a n >
2017-08-05 22:25:25 +12:00
)
}
}
2016-10-27 16:58:11 +13:00
2017-08-05 22:25:25 +12:00
renderSendAuthorizationButton ( ) {
if ( ! this . props . spotify . authorization ) return null
2016-10-25 14:09:53 +13:00
2017-08-05 22:25:25 +12:00
return (
< button onClick = { e => this . props . uiActions . openModal ( 'send_authorization' , { } ) } >
Share authentication
< / b u t t o n >
)
}
2017-11-13 16:52:53 +13:00
renderServerStatus ( ) {
var colour = 'grey' ;
var icon = 'question-circle' ;
var status = 'Unknown' ;
if ( this . props . mopidy . connecting || this . props . pusher . connecting ) {
icon = 'plug' ;
status = 'Connecting...'
} else if ( ! this . props . mopidy . connected || ! this . props . pusher . connected ) {
colour = 'red' ;
icon = 'close' ;
status = 'Disconnected' ;
} else if ( this . props . mopidy . connected && this . props . pusher . connected ) {
colour = 'green' ;
icon = 'check' ;
status = 'Connected' ;
2017-08-04 09:19:19 +12:00
}
2017-08-06 12:20:43 +12:00
return (
2017-11-13 16:52:53 +13:00
< span className = { colour + '-text' } >
< FontAwesome name = { icon } / > & nbsp ; { status }
< / s p a n >
) ;
}
renderSpotifyStatus ( ) {
var colour = 'grey' ;
var icon = 'question-circle' ;
var status = 'Unknown' ;
if ( this . props . spotify . connecting ) {
icon = 'plug' ;
status = 'Connecting...'
} else if ( ! this . props . spotify . connected ) {
colour = 'red' ;
icon = 'close' ;
status = 'Disconnected' ;
} else if ( this . props . mopidy . connected ) {
colour = 'green' ;
icon = 'check' ;
status = 'Connected' ;
}
if ( ! this . props . mopidy . uri _schemes || ! this . props . mopidy . uri _schemes . includes ( 'spotify:' ) ) {
colour = 'orange' ;
status += ' (Mopidy-Spotify extension not installed/enabled!)' ;
}
return (
< span className = { colour + '-text' } >
< FontAwesome name = { icon } / > & nbsp ; { status }
< / s p a n >
) ;
2017-08-04 09:19:19 +12:00
}
2017-06-28 08:36:09 +12:00
2017-08-04 09:19:19 +12:00
render ( ) {
2017-08-05 22:25:25 +12:00
var options = (
< span >
< button className = "no-hover" onClick = { e => hashHistory . push ( global . baseURL + 'settings/debug' ) } >
< FontAwesome name = "flask" / > & nbsp ;
Debug
2017-09-04 11:25:58 +12:00
{ this . props . ui && this . props . ui . test _mode ? < span className = "flag warning" > Test mode < / s p a n > : n u l l }
2017-08-05 22:25:25 +12:00
< / b u t t o n >
< a className = "no-hover button" href = "https://github.com/jaedb/Iris/wiki" target = "_blank" >
< FontAwesome name = "question" / > & nbsp ;
Help
< / a >
< / s p a n >
)
2017-08-04 09:19:19 +12:00
return (
< div className = "view settings-view" >
2017-08-06 20:22:16 +12:00
< Header className = "overlay" icon = "cog" title = "Settings" options = { options } uiActions = { this . props . uiActions } / >
2016-10-29 22:40:02 +13:00
2017-08-04 16:08:57 +12:00
< div className = "intro" >
< div className = "liner" >
2017-11-28 08:39:34 +13:00
< Parallax image = "assets/backgrounds/settings.jpg" / >
2017-08-04 16:08:57 +12:00
< / d i v >
< / d i v >
2017-01-04 16:14:10 +13:00
2017-08-04 16:08:57 +12:00
< section className = "content-wrapper" >
2017-01-04 16:14:10 +13:00
2017-11-13 16:52:53 +13:00
< h4 className = "underline" > Server < / h 4 >
2017-11-04 14:03:59 +13:00
2017-11-13 16:52:53 +13:00
< div className = "field" >
< div className = "name" > Status < / d i v >
< div className = "input" >
< div className = "text" >
{ this . renderServerStatus ( ) }
< / d i v >
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
< div className = "field" >
< div className = "name" > Username < / d i v >
< div className = "input" >
< input
type = "text"
onChange = { e => this . handleUsernameChange ( e . target . value ) }
onFocus = { e => this . setState ( { input _in _focus : 'pusher_username' } ) }
onBlur = { e => this . handleUsernameBlur ( e ) }
value = { this . state . pusher _username } / >
2017-09-27 15:39:55 +13:00
< div className = "description" >
A non - unique string used to identify this client ( no special characters )
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
2017-11-27 16:38:33 +13:00
< form onSubmit = { ( e ) => this . setConfig ( e ) } >
2017-08-05 22:25:25 +12:00
< div className = "field" >
< div className = "name" > Host < / d i v >
< div className = "input" >
< input
type = "text"
onChange = { e => 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 } / >
< / d i v >
< / d i v >
< div className = "field" >
< div className = "name" > Port < / d i v >
< div className = "input" >
< input
type = "text"
onChange = { e => 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 } / >
< / d i v >
< / d i v >
2017-11-27 16:38:33 +13:00
< div className = "field checkbox" >
< div className = "name" > Encryption < / d i v >
< div className = "input" >
< label >
< input
type = "checkbox"
name = "ssl"
checked = { this . state . mopidy _ssl }
onChange = { e => this . setState ( { mopidy _ssl : ! this . state . mopidy _ssl } ) } / >
< span className = "label has-tooltip" >
Enable SSL
< span className = "tooltip" > Requires SSL proxy < / s p a n >
< / s p a n >
< / l a b e l >
< / d i v >
< / d i v >
2017-08-05 22:25:25 +12:00
{ this . renderApplyButton ( ) }
< / f o r m >
< h4 className = "underline" > Localization < / h 4 >
< div className = "field" >
< div className = "name" > Country < / d i v >
< div className = "input" >
< input
type = "text"
onChange = { e => this . setState ( { country : e . target . value } ) }
onFocus = { e => this . setState ( { input _in _focus : 'country' } ) }
onBlur = { e => this . handleBlur ( 'country' , e . target . value ) }
value = { this . state . country } / >
2017-09-27 15:39:55 +13:00
< div className = "description" >
An < a href = "http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2" target = "_blank" > ISO 3166 - 1 alpha - 2 < / a > c o u n t r y c o d e ( e g < e m > N Z < / e m > )
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
< div className = "field" >
< div className = "name" > Locale < / d i v >
< div className = "input" >
< input
type = "text"
onChange = { e => this . setState ( { locale : e . target . value } ) }
onFocus = { e => this . setState ( { input _in _focus : 'locale' } ) }
onBlur = { e => this . handleBlur ( 'locale' , e . target . value ) }
value = { this . state . locale } / >
2017-09-27 15:39:55 +13:00
< div className = "description" >
2017-09-29 08:56:30 +13:00
Lowercase < a href = "http://en.wikipedia.org/wiki/ISO_639" target = "_blank" > ISO 639 language code < /a> and an uppercase <a href="http:/ / en . wikipedia . org / wiki / ISO _3166 - 1_ alpha - 2 " target=" _blank " > ISO 3166 - 1 alpha - 2 country code < / a > , j o i n e d b y a n u n d e r s c o r e ( e g < e m > e n _ N Z < / e m > )
2017-09-27 15:39:55 +13:00
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
< h4 className = "underline" > Spotify < / h 4 >
2017-09-29 08:56:30 +13:00
2017-11-13 16:52:53 +13:00
< div className = "field" >
< div className = "name" > Status < / d i v >
< div className = "input" >
< div className = "text" >
{ this . renderSpotifyStatus ( ) }
< / d i v >
< / d i v >
< / d i v >
2017-08-05 22:25:25 +12:00
< div className = "field current-user" >
< div className = "name" > Current user < / d i v >
< div className = "input" >
< div className = "text" >
{ this . renderSpotifyUser ( ) }
< / d i v >
< / d i v >
2017-09-29 08:56:30 +13:00
< / d i v >
2017-11-03 09:06:41 +13:00
2017-09-29 08:56:30 +13:00
< div className = "field" >
< div className = "name" > Authorization < / d i v >
< div className = "input" >
< SpotifyAuthenticationFrame / >
{ this . renderSendAuthorizationButton ( ) }
{ this . props . spotify . refreshing _token ? < button className = "working" > Refreshing ... < / b u t t o n > : < b u t t o n o n C l i c k = { e = > t h i s . p r o p s . s p o t i f y A c t i o n s . r e f r e s h i n g T o k e n ( ) } > F o r c e t o k e n r e f r e s h < / b u t t o n > }
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
2017-11-02 21:20:56 +13:00
< h4 className = "underline" > LastFM < / h 4 >
2017-11-03 09:06:41 +13:00
{ this . props . lastfm . session ? < div className = "field current-user" >
< div className = "name" > Current user < / d i v >
< div className = "input" >
< div className = "text" >
{ this . renderLastfmUser ( ) }
< / d i v >
< / d i v >
< / d i v > : n u l l }
2017-11-02 21:20:56 +13:00
< div className = "field" >
< div className = "name" > Authorization < / d i v >
< div className = "input" >
< LastfmAuthenticationFrame / >
< / d i v >
< / d i v >
2017-08-05 22:25:25 +12:00
< h4 className = "underline" > Advanced < / h 4 >
< div className = "field checkbox" >
< div className = "name" > UI behavior < / d i v >
< div className = "input" >
< label >
< input
type = "checkbox"
name = "log_actions"
checked = { this . props . ui . clear _tracklist _on _play }
onChange = { e => this . props . uiActions . set ( { clear _tracklist _on _play : ! this . props . ui . clear _tracklist _on _play } ) } / >
2017-11-19 20:38:36 +13:00
< span className = "label has-tooltip" >
Clear tracklist on play of URI ( s )
< span className = "tooltip" > Playing one or more URIs will clear the current play queue first < / s p a n >
< / s p a n >
< / l a b e l >
< label >
< input
type = "checkbox"
name = "log_actions"
checked = { this . props . core . anonymise _analytics }
onChange = { e => this . props . coreActions . set ( { anonymise _analytics : ! this . props . core . anonymise _analytics } ) } / >
< span className = "label has-tooltip" >
Exclude personal data from collection
< span className = "tooltip" > Personal data used for debugging Iris is not collected by Google Analytics < / s p a n >
< / s p a n >
2017-08-05 22:25:25 +12:00
< / l a b e l >
< / d i v >
< / d i v >
< div className = "field pusher-connections" >
< div className = "name" > Connections < / d i v >
< div className = "input" >
2017-08-06 21:12:57 +12:00
< div className = "text" >
2017-08-05 22:25:25 +12:00
< PusherConnectionList / >
2017-08-06 21:12:57 +12:00
< / d i v >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
< div className = "field" >
< div className = "name" > Extensions < / d i v >
< div className = "input" >
2017-08-06 21:12:57 +12:00
< div className = "text" >
< URISchemesList / >
< / d i v >
< / d i v >
< / d i v >
< div className = "field" >
< div className = "name" > Version < / d i v >
< div className = "input" >
< VersionManager / >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
< div className = "field" >
< div className = "name" > Reset < / d i v >
< div className = "input" >
< ConfirmationButton className = "destructive" content = "Reset all settings" confirmingContent = "Are you sure?" onConfirm = { ( ) => this . resetAllSettings ( ) } / >
< / d i v >
< / d i v >
< h4 className = "underline" > About < / h 4 >
< div className = "field" >
< div >
< em > < a href = "https://github.com/jaedb/Iris" target = "_blank" > Iris < / a > < / e m > i s a n o p e n - s o u r c e p r o j e c t b y < a h r e f = " h t t p s : / / g i t h u b . c o m / j a e d b " t a r g e t = " _ b l a n k " > J a m e s B a r n s l e y < / a > . I t i s p r o v i d e d f r e e a n d w i t h a b s o l u t e l y n o w a r r a n t y . I f y o u p a i d s o m e o n e f o r t h i s s o f t w a r e , p l e a s e l e t m e k n o w .
< br / >
< br / >
2017-11-13 21:19:02 +13:00
Google Analytics is used to help trace issues and provide valuable insight into how we can continue to make improvements . This may include personal information ( eg Spotify Username ) . For more information , see < a href = "https://github.com/jaedb/Iris/wiki/Terms-of-use" target = "_blank" > terms and conditions < / a > .
2017-08-05 22:25:25 +12:00
< br / >
< / d i v >
< br / > < br / >
< div >
< a className = "button" href = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=james%40barnsley%2enz&lc=NZ&item_name=James%20Barnsley¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted" target = "_blank" >
< FontAwesome name = "paypal" / > & nbsp ; Donate
< / a >
& nbsp ; & nbsp ;
< a className = "button" href = "https://github.com/jaedb/Iris" target = "_blank" >
< FontAwesome name = "github" / > & nbsp ; GitHub
< / a >
& nbsp ; & nbsp ;
2017-11-21 08:07:00 +13:00
< a className = "button" href = "http://creativecommons.org/licenses/by-nc/4.0/" target = "_blank" > < FontAwesome name = "creative-commons" / > & nbsp ; Licence < / a >
2017-08-05 22:25:25 +12:00
< / d i v >
< / d i v >
< / s e c t i o n >
2016-10-17 10:39:11 +13:00
< / d i v >
) ;
}
2017-08-05 22:25:25 +12:00
}
const mapStateToProps = ( state , ownProps ) => {
return state ;
}
const mapDispatchToProps = ( dispatch ) => {
return {
coreActions : bindActionCreators ( coreActions , dispatch ) ,
uiActions : bindActionCreators ( uiActions , dispatch ) ,
pusherActions : bindActionCreators ( pusherActions , dispatch ) ,
mopidyActions : bindActionCreators ( mopidyActions , dispatch ) ,
2017-11-03 09:06:41 +13:00
lastfmActions : bindActionCreators ( lastfmActions , dispatch ) ,
2017-08-05 22:25:25 +12:00
spotifyActions : bindActionCreators ( spotifyActions , dispatch )
}
}
export default connect ( mapStateToProps , mapDispatchToProps ) ( Settings )