2017-11-12 02:44:26 +02:00
const React = require ( 'react' ) ;
const { connect } = require ( 'react-redux' ) ;
2017-12-14 20:12:14 +02:00
const Setting = require ( 'lib/models/Setting.js' ) ;
2017-11-12 02:44:26 +02:00
const { bridge } = require ( 'electron' ) . remote . require ( './bridge' ) ;
const { themeStyle } = require ( '../theme.js' ) ;
2017-12-08 23:51:59 +02:00
const pathUtils = require ( 'lib/path-utils.js' ) ;
2017-11-12 02:44:26 +02:00
const { _ } = require ( 'lib/locale.js' ) ;
2018-02-06 20:59:36 +02:00
const SyncTargetRegistry = require ( 'lib/SyncTargetRegistry' ) ;
const shared = require ( 'lib/components/shared/config-shared.js' ) ;
2017-11-12 02:44:26 +02:00
class ConfigScreenComponent extends React . Component {
2017-12-08 00:29:02 +02:00
constructor ( ) {
super ( ) ;
2018-02-06 20:59:36 +02:00
shared . init ( this ) ;
this . checkSyncConfig _ = async ( ) => {
await shared . checkSyncConfig ( this , this . state . settings ) ;
2019-07-29 14:13:23 +02:00
} ;
2018-02-06 20:59:36 +02:00
this . rowStyle _ = {
marginBottom : 10 ,
} ;
2017-12-08 00:29:02 +02:00
}
componentWillMount ( ) {
this . setState ( { settings : this . props . settings } ) ;
}
2017-12-17 13:30:32 +02:00
keyValueToArray ( kv ) {
let output = [ ] ;
for ( let k in kv ) {
if ( ! kv . hasOwnProperty ( k ) ) continue ;
output . push ( {
key : k ,
label : kv [ k ] ,
} ) ;
}
return output ;
}
2019-01-28 01:15:56 +02:00
sectionToComponent ( key , section , settings ) {
const theme = themeStyle ( this . props . theme ) ;
const settingComps = [ ] ;
for ( let i = 0 ; i < section . metadatas . length ; i ++ ) {
const md = section . metadatas [ i ] ;
const settingComp = this . settingToComponent ( md . key , settings [ md . key ] ) ;
settingComps . push ( settingComp ) ;
}
const sectionStyle = {
marginBottom : 20 ,
} ;
2019-02-10 18:29:06 +02:00
const headerStyle = Object . assign ( { } , theme . headerStyle , {
borderBottomWidth : 1 ,
borderBottomColor : theme . dividerColor ,
borderBottomStyle : 'solid' ,
paddingBottom : '.4em' ,
} ) ;
2019-01-28 01:15:56 +02:00
if ( section . name === 'general' ) {
sectionStyle . borderTopWidth = 0 ;
}
2019-07-29 14:13:23 +02:00
const noteComp = section . name !== 'general' ? null : < div style = { Object . assign ( { } , theme . textStyle , { marginBottom : 10 } ) } > { _ ( 'Notes and settings are stored in: %s' , pathUtils . toSystemSlashes ( Setting . value ( 'profileDir' ) , process . platform ) ) } < / div > ;
2019-01-28 01:15:56 +02:00
2019-05-08 00:50:12 +02:00
if ( section . name === 'sync' ) {
const syncTargetMd = SyncTargetRegistry . idToMetadata ( settings [ 'sync.target' ] ) ;
if ( syncTargetMd . supportsConfigCheck ) {
const messages = shared . checkSyncConfigMessages ( this ) ;
const statusStyle = Object . assign ( { } , theme . textStyle , { marginTop : 10 } ) ;
const statusComp = ! messages . length ? null : (
< div style = { statusStyle } >
{ messages [ 0 ] }
2019-07-29 14:13:23 +02:00
{ messages . length >= 1 ? < p > { messages [ 1 ] } < / p > : null }
< / div >
) ;
2019-05-08 00:50:12 +02:00
settingComps . push (
< div key = "check_sync_config_button" style = { this . rowStyle _ } >
2019-07-29 14:13:23 +02:00
< button disabled = { this . state . checkSyncConfigResult === 'checking' } style = { theme . buttonStyle } onClick = { this . checkSyncConfig _ } >
{ _ ( 'Check synchronisation configuration' ) }
< / button >
{ statusComp }
< / div >
) ;
2019-05-08 00:50:12 +02:00
}
}
2019-01-28 01:15:56 +02:00
return (
< div key = { key } style = { sectionStyle } >
2019-02-10 18:29:06 +02:00
< h2 style = { headerStyle } > { Setting . sectionNameToLabel ( section . name ) } < / h2 >
2019-01-28 01:15:56 +02:00
{ noteComp }
2019-07-29 14:13:23 +02:00
< div > { settingComps } < / div >
2019-01-28 01:15:56 +02:00
< / div >
) ;
}
2017-11-12 02:44:26 +02:00
settingToComponent ( key , value ) {
const theme = themeStyle ( this . props . theme ) ;
let output = null ;
2018-02-06 20:59:36 +02:00
const rowStyle = this . rowStyle _ ;
2017-11-12 02:44:26 +02:00
const labelStyle = Object . assign ( { } , theme . textStyle , {
display : 'inline-block' ,
marginRight : 10 ,
2018-11-08 00:37:13 +02:00
color : theme . color ,
2017-11-12 02:44:26 +02:00
} ) ;
2019-01-30 21:19:06 +02:00
const subLabel = Object . assign ( { } , labelStyle , {
opacity : 0.7 ,
marginBottom : Math . round ( rowStyle . marginBottom * 0.7 ) ,
} ) ;
const invisibleLabel = Object . assign ( { } , labelStyle , {
opacity : 0 ,
} ) ;
2017-11-12 02:44:26 +02:00
const controlStyle = {
display : 'inline-block' ,
2018-11-08 00:37:13 +02:00
color : theme . color ,
backgroundColor : theme . backgroundColor ,
2017-11-12 02:44:26 +02:00
} ;
2018-03-02 20:16:48 +02:00
const descriptionStyle = Object . assign ( { } , theme . textStyle , {
color : theme . colorFaded ,
marginTop : 5 ,
fontStyle : 'italic' ,
2018-06-26 00:54:28 +02:00
maxWidth : '70em' ,
2018-03-02 20:16:48 +02:00
} ) ;
2017-11-12 02:44:26 +02:00
const updateSettingValue = ( key , value ) => {
2019-01-30 21:19:06 +02:00
// console.info(key + ' = ' + value);
2018-02-13 20:26:33 +02:00
return shared . updateSettingValue ( this , key , value ) ;
2019-07-29 14:13:23 +02:00
} ;
2017-11-12 02:44:26 +02:00
2017-11-30 20:36:26 +02:00
// Component key needs to be key+value otherwise it doesn't update when the settings change.
2017-11-12 02:44:26 +02:00
const md = Setting . settingMetadata ( key ) ;
2018-03-02 20:16:48 +02:00
const descriptionText = Setting . keyDescription ( key , 'desktop' ) ;
2019-07-29 14:13:23 +02:00
const descriptionComp = descriptionText ? < div style = { descriptionStyle } > { descriptionText } < / div > : null ;
2018-03-02 20:16:48 +02:00
2017-11-12 02:44:26 +02:00
if ( md . isEnum ) {
let items = [ ] ;
const settingOptions = md . options ( ) ;
2017-12-17 13:30:32 +02:00
let array = this . keyValueToArray ( settingOptions ) ;
for ( let i = 0 ; i < array . length ; i ++ ) {
const e = array [ i ] ;
2019-07-29 14:13:23 +02:00
items . push (
< option value = { e . key . toString ( ) } key = { e . key } >
{ settingOptions [ e . key ] }
< / option >
) ;
2017-11-12 02:44:26 +02:00
}
return (
2017-12-15 09:31:57 +02:00
< div key = { key } style = { rowStyle } >
2019-07-29 14:13:23 +02:00
< div style = { labelStyle } >
< label > { md . label ( ) } < / label >
< / div >
< select
value = { value }
style = { controlStyle }
onChange = { event => {
updateSettingValue ( key , event . target . value ) ;
} }
>
2017-11-12 02:44:26 +02:00
{ items }
< / select >
2019-07-29 14:13:23 +02:00
{ descriptionComp }
2017-11-12 02:44:26 +02:00
< / div >
) ;
} else if ( md . type === Setting . TYPE _BOOL ) {
2019-07-29 14:13:23 +02:00
const onCheckboxClick = event => {
updateSettingValue ( key , ! value ) ;
} ;
2017-12-08 00:29:02 +02:00
2018-01-23 20:31:49 +02:00
// Hack: The {key+value.toString()} is needed as otherwise the checkbox doesn't update when the state changes.
// There's probably a better way to do this but can't figure it out.
2017-11-12 02:44:26 +02:00
return (
2019-07-29 14:13:23 +02:00
< div key = { key + value . toString ( ) } style = { rowStyle } >
2017-11-12 02:44:26 +02:00
< div style = { controlStyle } >
2019-07-29 14:13:23 +02:00
< input
id = { 'setting_checkbox_' + key }
type = "checkbox"
checked = { ! ! value }
onChange = { event => {
onCheckboxClick ( event ) ;
} }
/ >
< label
onClick = { event => {
onCheckboxClick ( event ) ;
} }
style = { labelStyle }
htmlFor = { 'setting_checkbox_' + key }
>
{ md . label ( ) }
< / label >
{ descriptionComp }
2017-11-12 02:44:26 +02:00
< / div >
< / div >
) ;
2017-12-08 00:29:02 +02:00
} else if ( md . type === Setting . TYPE _STRING ) {
2018-11-08 00:37:13 +02:00
const inputStyle = Object . assign ( { } , controlStyle , {
width : '50%' ,
minWidth : '20em' ,
2019-07-29 14:13:23 +02:00
border : '1px solid' ,
} ) ;
2018-01-26 00:44:09 +02:00
const inputType = md . secure === true ? 'password' : 'text' ;
2019-01-30 21:19:06 +02:00
if ( md . subType === 'file_path_and_args' ) {
inputStyle . marginBottom = subLabel . marginBottom ;
const splitCmd = cmdString => {
const path = pathUtils . extractExecutablePath ( cmdString ) ;
const args = cmdString . substr ( path . length + 1 ) ;
return [ pathUtils . unquotePath ( path ) , args ] ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
const joinCmd = cmdArray => {
if ( ! cmdArray [ 0 ] && ! cmdArray [ 1 ] ) return '' ;
let cmdString = pathUtils . quotePath ( cmdArray [ 0 ] ) ;
if ( ! cmdString ) cmdString = '""' ;
if ( cmdArray [ 1 ] ) cmdString += ' ' + cmdArray [ 1 ] ;
return cmdString ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
const onPathChange = event => {
const cmd = splitCmd ( this . state . settings [ key ] ) ;
cmd [ 0 ] = event . target . value ;
updateSettingValue ( key , joinCmd ( cmd ) ) ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
const onArgsChange = event => {
const cmd = splitCmd ( this . state . settings [ key ] ) ;
cmd [ 1 ] = event . target . value ;
updateSettingValue ( key , joinCmd ( cmd ) ) ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
const browseButtonClick = ( ) => {
const paths = bridge ( ) . showOpenDialog ( ) ;
if ( ! paths || ! paths . length ) return ;
const cmd = splitCmd ( this . state . settings [ key ] ) ;
2019-07-29 14:13:23 +02:00
cmd [ 0 ] = paths [ 0 ] ;
2019-01-30 21:19:06 +02:00
updateSettingValue ( key , joinCmd ( cmd ) ) ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
const cmd = splitCmd ( this . state . settings [ key ] ) ;
return (
< div key = { key } style = { rowStyle } >
2019-07-29 14:13:23 +02:00
< div style = { { display : 'flex' } } >
< div style = { { flex : 0 , whiteSpace : 'nowrap' } } >
< div style = { labelStyle } >
< label > { md . label ( ) } < / label >
< / div >
2019-01-30 21:19:06 +02:00
< / div >
2019-07-29 14:13:23 +02:00
< div style = { { flex : 0 } } >
2019-01-30 21:19:06 +02:00
< div style = { subLabel } > Path : < / div >
< div style = { subLabel } > Arguments : < / div >
< / div >
2019-07-29 14:13:23 +02:00
< div style = { { flex : 1 } } >
< div style = { { display : 'flex' , flexDirection : 'row' , alignItems : 'center' , marginBottom : inputStyle . marginBottom } } >
< input
type = { inputType }
style = { Object . assign ( { } , inputStyle , { marginBottom : 0 } ) }
onChange = { event => {
onPathChange ( event ) ;
} }
value = { cmd [ 0 ] }
/ >
< button onClick = { browseButtonClick } style = { Object . assign ( { } , theme . buttonStyle , { marginLeft : 5 , minHeight : 20 , height : 20 } ) } >
{ _ ( 'Browse...' ) }
< / button >
2019-01-30 21:19:06 +02:00
< / div >
2019-07-29 14:13:23 +02:00
< input
type = { inputType }
style = { inputStyle }
onChange = { event => {
onArgsChange ( event ) ;
} }
value = { cmd [ 1 ] }
/ >
2019-01-30 21:19:06 +02:00
< / div >
< / div >
2019-07-29 14:13:23 +02:00
< div style = { { display : 'flex' } } >
< div style = { { flex : 0 , whiteSpace : 'nowrap' } } >
< div style = { invisibleLabel } >
< label > { md . label ( ) } < / label >
< / div >
2019-01-30 21:19:06 +02:00
< / div >
2019-07-29 14:13:23 +02:00
< div style = { { flex : 1 } } > { descriptionComp } < / div >
2019-01-30 21:19:06 +02:00
< / div >
< / div >
) ;
} else {
2019-07-29 14:13:23 +02:00
const onTextChange = event => {
2019-01-30 21:19:06 +02:00
updateSettingValue ( key , event . target . value ) ;
2019-07-29 14:13:23 +02:00
} ;
2019-01-30 21:19:06 +02:00
return (
< div key = { key } style = { rowStyle } >
2019-07-29 14:13:23 +02:00
< div style = { labelStyle } >
< label > { md . label ( ) } < / label >
< / div >
< input
type = { inputType }
style = { inputStyle }
value = { this . state . settings [ key ] }
onChange = { event => {
onTextChange ( event ) ;
} }
/ >
{ descriptionComp }
2019-01-30 21:19:06 +02:00
< / div >
) ;
}
2018-01-19 14:27:44 +02:00
} else if ( md . type === Setting . TYPE _INT ) {
2019-07-29 14:13:23 +02:00
const onNumChange = event => {
2018-01-23 20:31:49 +02:00
updateSettingValue ( key , event . target . value ) ;
2018-01-19 14:27:44 +02:00
} ;
2019-05-06 22:35:29 +02:00
const label = [ md . label ( ) ] ;
if ( md . unitLabel ) label . push ( '(' + md . unitLabel ( ) + ')' ) ;
2018-01-19 14:27:44 +02:00
return (
2018-01-23 20:31:49 +02:00
< div key = { key } style = { rowStyle } >
2019-07-29 14:13:23 +02:00
< div style = { labelStyle } >
< label > { label . join ( ' ' ) } < / label >
< / div >
< input
type = "number"
style = { controlStyle }
value = { this . state . settings [ key ] }
onChange = { event => {
onNumChange ( event ) ;
} }
min = { md . minimum }
max = { md . maximum }
step = { md . step }
/ >
{ descriptionComp }
2018-01-23 20:31:49 +02:00
< / div >
2018-01-19 14:27:44 +02:00
) ;
2017-12-08 00:29:02 +02:00
} else {
console . warn ( 'Type not implemented: ' + key ) ;
2017-11-12 02:44:26 +02:00
}
return output ;
}
2018-06-26 00:54:28 +02:00
onApplyClick ( ) {
shared . saveSettings ( this ) ;
}
2017-12-08 00:29:02 +02:00
onSaveClick ( ) {
2018-02-13 20:26:33 +02:00
shared . saveSettings ( this ) ;
2017-12-08 00:29:02 +02:00
this . props . dispatch ( { type : 'NAV_BACK' } ) ;
}
onCancelClick ( ) {
this . props . dispatch ( { type : 'NAV_BACK' } ) ;
}
2017-11-12 02:44:26 +02:00
render ( ) {
const theme = themeStyle ( this . props . theme ) ;
2019-01-28 01:44:16 +02:00
2019-07-29 14:13:23 +02:00
const style = Object . assign (
{
backgroundColor : theme . backgroundColor ,
} ,
this . props . style ,
{
overflow : 'hidden' ,
display : 'flex' ,
flexDirection : 'column' ,
}
) ;
2017-11-12 02:44:26 +02:00
2019-01-28 01:44:16 +02:00
let settings = this . state . settings ;
2017-11-12 02:44:26 +02:00
2019-01-28 01:15:56 +02:00
const containerStyle = Object . assign ( { } , theme . containerStyle , { padding : 10 , paddingTop : 0 } ) ;
2017-11-12 02:44:26 +02:00
2019-01-28 01:44:16 +02:00
const hasChanges = ! ! this . state . changedSettingKeys . length ;
2018-11-08 00:37:13 +02:00
const buttonStyle = Object . assign ( { } , theme . buttonStyle , {
2019-01-28 01:44:16 +02:00
display : 'inline-block' ,
2017-12-08 00:29:02 +02:00
marginRight : 10 ,
2018-11-08 00:37:13 +02:00
} ) ;
2017-12-08 00:29:02 +02:00
2019-01-28 01:44:16 +02:00
const buttonStyleApprove = Object . assign ( { } , buttonStyle , {
opacity : hasChanges ? 1 : theme . disabledOpacity ,
} ) ;
2019-01-28 01:15:56 +02:00
const settingComps = shared . settingsToComponents2 ( this , 'desktop' , settings ) ;
2017-11-12 02:44:26 +02:00
2019-01-28 01:44:16 +02:00
const buttonBarStyle = {
display : 'flex' ,
alignItems : 'center' ,
padding : 15 ,
2019-02-10 18:29:06 +02:00
borderBottomWidth : 1 ,
borderBottomStyle : 'solid' ,
borderBottomColor : theme . dividerColor ,
2019-01-28 01:44:16 +02:00
} ;
2017-11-12 02:44:26 +02:00
return (
< div style = { style } >
2019-01-28 01:44:16 +02:00
< div style = { buttonBarStyle } >
2019-07-29 14:13:23 +02:00
< button
onClick = { ( ) => {
this . onCancelClick ( ) ;
} }
style = { buttonStyle }
>
< i style = { theme . buttonIconStyle } className = { 'fa fa-chevron-left' } > < / i >
{ _ ( 'Cancel' ) }
< / button >
< button
disabled = { ! hasChanges }
onClick = { ( ) => {
this . onSaveClick ( ) ;
} }
style = { buttonStyleApprove }
>
{ _ ( 'OK' ) }
< / button >
< button
disabled = { ! hasChanges }
onClick = { ( ) => {
this . onApplyClick ( ) ;
} }
style = { buttonStyleApprove }
>
{ _ ( 'Apply' ) }
< / button >
2019-02-10 18:29:06 +02:00
< / div >
2019-07-29 14:13:23 +02:00
< div style = { containerStyle } > { settingComps } < / div >
2017-11-12 02:44:26 +02:00
< / div >
) ;
}
}
2019-07-29 14:13:23 +02:00
const mapStateToProps = state => {
2017-11-12 02:44:26 +02:00
return {
theme : state . settings . theme ,
settings : state . settings ,
locale : state . settings . locale ,
} ;
} ;
const ConfigScreen = connect ( mapStateToProps ) ( ConfigScreenComponent ) ;
2018-11-08 00:37:13 +02:00
module . exports = { ConfigScreen } ;