2020-07-27 19:43:30 +02:00
// @flow
import * as React from 'react' ;
import { FormField , FormFieldPrice } from 'component/common/form' ;
import Button from 'component/button' ;
import I18nMessage from 'component/i18nMessage' ;
import Page from 'component/page' ;
import SettingWalletServer from 'component/settingWalletServer' ;
import SettingAutoLaunch from 'component/settingAutoLaunch' ;
2020-08-13 18:57:00 +02:00
import SettingClosingBehavior from 'component/settingClosingBehavior' ;
2020-07-27 19:43:30 +02:00
import FileSelector from 'component/common/file-selector' ;
import { SETTINGS } from 'lbry-redux' ;
import Card from 'component/common/card' ;
import { getPasswordFromCookie } from 'util/saved-passwords' ;
import Spinner from 'component/spinner' ;
// @if TARGET='app'
const IS _MAC = process . platform === 'darwin' ;
// @endif
type Price = {
currency : string ,
amount : number ,
} ;
type SetDaemonSettingArg = boolean | string | number | Price ;
type DaemonSettings = {
download _dir : string ,
share _usage _data : boolean ,
max _key _fee ? : Price ,
max _connections _per _download ? : number ,
save _files : boolean ,
save _blobs : boolean ,
ffmpeg _path : string ,
} ;
type Props = {
setDaemonSetting : ( string , ? SetDaemonSettingArg ) => void ,
clearDaemonSetting : string => void ,
setClientSetting : ( string , SetDaemonSettingArg ) => void ,
daemonSettings : DaemonSettings ,
isAuthenticated : boolean ,
instantPurchaseEnabled : boolean ,
instantPurchaseMax : Price ,
encryptWallet : ( ) => void ,
decryptWallet : ( ) => void ,
updateWalletStatus : ( ) => void ,
walletEncrypted : boolean ,
hideBalance : boolean ,
confirmForgetPassword : ( { } ) => void ,
ffmpegStatus : { available : boolean , which : string } ,
findingFFmpeg : boolean ,
findFFmpeg : ( ) => void ,
language ? : string ,
syncEnabled : boolean ,
syncSettings : ( ) => void ,
2020-09-04 17:02:30 +02:00
enterSettings : ( ) => void ,
exitSettings : ( ) => void ,
2020-07-27 19:43:30 +02:00
} ;
type State = {
clearingCache : boolean ,
storedPassword : boolean ,
} ;
class SettingsPage extends React . PureComponent < Props , State > {
constructor ( props : Props ) {
super ( props ) ;
this . state = {
clearingCache : false ,
storedPassword : false ,
} ;
( this : any ) . onKeyFeeChange = this . onKeyFeeChange . bind ( this ) ;
( this : any ) . onMaxConnectionsChange = this . onMaxConnectionsChange . bind ( this ) ;
( this : any ) . onKeyFeeDisableChange = this . onKeyFeeDisableChange . bind ( this ) ;
( this : any ) . onInstantPurchaseMaxChange = this . onInstantPurchaseMaxChange . bind ( this ) ;
( this : any ) . onThemeChange = this . onThemeChange . bind ( this ) ;
( this : any ) . onAutomaticDarkModeChange = this . onAutomaticDarkModeChange . bind ( this ) ;
( this : any ) . onConfirmForgetPassword = this . onConfirmForgetPassword . bind ( this ) ;
}
componentDidMount ( ) {
2020-09-04 17:02:30 +02:00
const { isAuthenticated , ffmpegStatus , daemonSettings , findFFmpeg , enterSettings } = this . props ;
2020-07-27 19:43:30 +02:00
// @if TARGET='app'
const { available } = ffmpegStatus ;
const { ffmpeg _path : ffmpegPath } = daemonSettings ;
if ( ! available ) {
if ( ffmpegPath ) {
this . clearDaemonSetting ( 'ffmpeg_path' ) ;
}
findFFmpeg ( ) ;
}
// @endif
if ( isAuthenticated || ! IS _WEB ) {
this . props . updateWalletStatus ( ) ;
getPasswordFromCookie ( ) . then ( p => {
if ( typeof p === 'string' ) {
this . setState ( { storedPassword : true } ) ;
}
} ) ;
}
2020-09-04 17:02:30 +02:00
enterSettings ( ) ;
}
componentWillUnmount ( ) {
const { exitSettings } = this . props ;
exitSettings ( ) ;
2020-07-27 19:43:30 +02:00
}
onFFmpegFolder ( path : string ) {
this . setDaemonSetting ( 'ffmpeg_path' , path ) ;
this . findFFmpeg ( ) ;
}
onKeyFeeChange ( newValue : Price ) {
this . setDaemonSetting ( 'max_key_fee' , newValue ) ;
}
onMaxConnectionsChange ( event : SyntheticInputEvent < * > ) {
const { value } = event . target ;
this . setDaemonSetting ( 'max_connections_per_download' , value ) ;
}
onKeyFeeDisableChange ( isDisabled : boolean ) {
if ( isDisabled ) this . setDaemonSetting ( 'max_key_fee' ) ;
}
onThemeChange ( event : SyntheticInputEvent < * > ) {
const { value } = event . target ;
if ( value === 'dark' ) {
this . onAutomaticDarkModeChange ( false ) ;
}
this . props . setClientSetting ( SETTINGS . THEME , value ) ;
}
onAutomaticDarkModeChange ( value : boolean ) {
this . props . setClientSetting ( SETTINGS . AUTOMATIC _DARK _MODE _ENABLED , value ) ;
}
onInstantPurchaseEnabledChange ( enabled : boolean ) {
this . props . setClientSetting ( SETTINGS . INSTANT _PURCHASE _ENABLED , enabled ) ;
}
onInstantPurchaseMaxChange ( newValue : Price ) {
this . props . setClientSetting ( SETTINGS . INSTANT _PURCHASE _MAX , newValue ) ;
}
onChangeEncryptWallet ( ) {
const { decryptWallet , walletEncrypted , encryptWallet } = this . props ;
if ( walletEncrypted ) {
decryptWallet ( ) ;
} else {
encryptWallet ( ) ;
}
}
onConfirmForgetPassword ( ) {
const { confirmForgetPassword } = this . props ;
confirmForgetPassword ( {
callback : ( ) => {
this . setState ( { storedPassword : false } ) ;
} ,
} ) ;
}
setDaemonSetting ( name : string , value : ? SetDaemonSettingArg ) : void {
this . props . setDaemonSetting ( name , value ) ;
}
clearDaemonSetting ( name : string ) : void {
this . props . clearDaemonSetting ( name ) ;
}
findFFmpeg ( ) : void {
this . props . findFFmpeg ( ) ;
}
render ( ) {
const {
daemonSettings ,
ffmpegStatus ,
instantPurchaseEnabled ,
instantPurchaseMax ,
isAuthenticated ,
walletEncrypted ,
setDaemonSetting ,
setClientSetting ,
hideBalance ,
findingFFmpeg ,
language ,
} = this . props ;
const { storedPassword } = this . state ;
const noDaemonSettings = ! daemonSettings || Object . keys ( daemonSettings ) . length === 0 ;
const defaultMaxKeyFee = { currency : 'USD' , amount : 50 } ;
const disableMaxKeyFee = ! ( daemonSettings && daemonSettings . max _key _fee ) ;
const connectionOptions = [ 1 , 2 , 4 , 6 , 10 , 20 ] ;
// @if TARGET='app'
const { available : ffmpegAvailable , which : ffmpegPath } = ffmpegStatus ;
// @endif
return (
< Page
noFooter
noSideNavigation
backout = { {
title : _ _ ( 'Advanced Settings' ) ,
backLabel : _ _ ( 'Done' ) ,
} }
className = "card-stack"
>
{ ! IS _WEB && noDaemonSettings ? (
< section className = "card card--section" >
< div className = "card__title card__title--deprecated" > { _ _ ( 'Failed to load settings.' ) } < / div >
< / section >
) : (
< div >
2020-07-29 06:16:49 +02:00
{ /* @if TARGET='app' */ }
2020-07-27 19:43:30 +02:00
< Card
title = { _ _ ( 'Network and Data Settings' ) }
actions = {
< React.Fragment >
< FormField
type = "checkbox"
name = "save_files"
onChange = { ( ) => setDaemonSetting ( 'save_files' , ! daemonSettings . save _files ) }
checked = { daemonSettings . save _files }
label = { _ _ ( 'Save all viewed content to your downloads directory' ) }
helper = { _ _ (
'Paid content and some file types are saved by default. Changing this setting will not affect previously downloaded content.'
) }
/ >
< FormField
type = "checkbox"
name = "save_blobs"
onChange = { ( ) => setDaemonSetting ( 'save_blobs' , ! daemonSettings . save _blobs ) }
checked = { daemonSettings . save _blobs }
label = { _ _ ( 'Save hosting data to help the LBRY network' ) }
helper = {
< React.Fragment >
{ _ _ ( "If disabled, LBRY will be very sad and you won't be helping improve the network." ) } { ' ' }
< Button button = "link" label = { _ _ ( 'Learn more' ) } href = "https://lbry.com/faq/host-content" / > .
< / React.Fragment >
}
/ >
< / React.Fragment >
}
/ >
< Card
title = { _ _ ( 'Max Purchase Price' ) }
actions = {
< React.Fragment >
< FormField
type = "radio"
name = "no_max_purchase_no_limit"
checked = { disableMaxKeyFee }
label = { _ _ ( 'No Limit' ) }
onChange = { ( ) => {
this . onKeyFeeDisableChange ( true ) ;
} }
/ >
< FormField
type = "radio"
name = "max_purchase_limit"
checked = { ! disableMaxKeyFee }
onChange = { ( ) => {
this . onKeyFeeDisableChange ( false ) ;
this . onKeyFeeChange ( defaultMaxKeyFee ) ;
} }
label = { _ _ ( 'Choose limit' ) }
/ >
{ ! disableMaxKeyFee && (
< FormFieldPrice
language = { language }
name = "max_key_fee"
min = { 0 }
onChange = { this . onKeyFeeChange }
price = { daemonSettings . max _key _fee ? daemonSettings . max _key _fee : defaultMaxKeyFee }
/ >
) }
< p className = "help" >
{ _ _ ( 'This will prevent you from purchasing any content over a certain cost, as a safety measure.' ) }
< / p >
< / React.Fragment >
}
/ >
{ /* @endif */ }
< Card
title = { _ _ ( 'Purchase and Tip Confirmations' ) }
actions = {
< React.Fragment >
< FormField
type = "radio"
name = "confirm_all_purchases"
checked = { ! instantPurchaseEnabled }
label = { _ _ ( 'Always confirm before purchasing content or tipping' ) }
onChange = { ( ) => {
this . onInstantPurchaseEnabledChange ( false ) ;
} }
/ >
< FormField
type = "radio"
name = "instant_purchases"
checked = { instantPurchaseEnabled }
label = { _ _ ( 'Only confirm purchases or tips over a certain amount' ) }
onChange = { ( ) => {
this . onInstantPurchaseEnabledChange ( true ) ;
} }
/ >
{ instantPurchaseEnabled && (
< FormFieldPrice
name = "confirmation_price"
min = { 0.1 }
onChange = { this . onInstantPurchaseMaxChange }
price = { instantPurchaseMax }
/ >
) }
< p className = "help" >
{ _ _ (
"When this option is chosen, LBRY won't ask you to confirm downloads or tips below your chosen amount."
) }
< / p >
< / React.Fragment >
}
/ >
{ ( isAuthenticated || ! IS _WEB ) && (
< Card
title = { _ _ ( 'Wallet Security' ) }
actions = {
< React.Fragment >
{ /* @if TARGET='app' */ }
< FormField
disabled
type = "checkbox"
name = "encrypt_wallet"
onChange = { ( ) => this . onChangeEncryptWallet ( ) }
checked = { walletEncrypted }
label = { _ _ ( 'Encrypt my wallet with a custom password' ) }
helper = {
< React.Fragment >
< I18nMessage
tokens = { {
learn _more : (
< Button
button = "link"
label = { _ _ ( 'Learn more' ) }
href = "https://lbry.com/faq/account-sync"
/ >
) ,
} }
>
Wallet encryption is currently unavailable until it ' s supported for synced accounts . It will
be added back soon . % learn _more % .
< / I18nMessage >
{ / * { _ _ ( ' S e c u r e y o u r l o c a l w a l l e t d a t a w i t h a c u s t o m p a s s w o r d . ' ) } { ' ' }
< strong > { _ _ ( 'Lost passwords cannot be recovered.' ) } < / strong >
< Button button = "link" label = { _ _ ( 'Learn more' ) } href = "https://lbry.com/faq/wallet-encryption" / > . * / }
< / React.Fragment >
}
/ >
{ walletEncrypted && storedPassword && (
< FormField
type = "checkbox"
name = "save_password"
onChange = { this . onConfirmForgetPassword }
checked = { storedPassword }
label = { _ _ ( 'Save Password' ) }
helper = { < React.Fragment > { _ _ ( 'Automatically unlock your wallet on startup' ) } < / React.Fragment > }
/ >
) }
{ /* @endif */ }
< FormField
type = "checkbox"
name = "hide_balance"
onChange = { ( ) => setClientSetting ( SETTINGS . HIDE _BALANCE , ! hideBalance ) }
checked = { hideBalance }
label = { _ _ ( 'Hide wallet balance in header' ) }
/ >
< / React.Fragment >
}
/ >
) }
{ /* @if TARGET='app' */ }
< Card
title = {
< span >
{ _ _ ( 'Automatic Transcoding' ) }
{ findingFFmpeg && < Spinner type = "small" / > }
< / span >
}
actions = {
< React.Fragment >
< FileSelector
type = "openDirectory"
placeholder = { _ _ ( 'A Folder containing FFmpeg' ) }
currentPath = { ffmpegPath || daemonSettings . ffmpeg _path }
onFileChosen = { ( newDirectory : WebFile ) => {
this . onFFmpegFolder ( newDirectory . path ) ;
} }
disabled = { Boolean ( ffmpegPath ) }
/ >
< p className = "help" >
{ ffmpegAvailable ? (
< I18nMessage
tokens = { {
learn _more : (
< Button
button = "link"
label = { _ _ ( 'Learn more' ) }
href = "https://lbry.com/faq/video-publishing-guide#automatic"
/ >
) ,
} }
>
FFmpeg is correctly configured . % learn _more %
< / I18nMessage >
) : (
< I18nMessage
tokens = { {
check _again : (
< Button
button = "link"
label = { _ _ ( 'Check again' ) }
onClick = { ( ) => this . findFFmpeg ( ) }
disabled = { findingFFmpeg }
/ >
) ,
learn _more : (
< Button
button = "link"
label = { _ _ ( 'Learn more' ) }
href = "https://lbry.com/faq/video-publishing-guide#automatic"
/ >
) ,
} }
>
FFmpeg could not be found . Navigate to it or Install , Then % check _again % or quit and restart the
app . % learn _more %
< / I18nMessage >
) }
< / p >
< / React.Fragment >
}
/ >
{ /* @endif */ }
{ ! IS _WEB && (
< Card
title = { _ _ ( 'Experimental Settings' ) }
actions = {
< React.Fragment >
{ /* @if TARGET='app' */ }
{ / *
Disabling below until we get downloads to work with shared subscriptions code
< FormField
type = "checkbox"
name = "auto_download"
onChange = { ( ) => setClientSetting ( SETTINGS . AUTO _DOWNLOAD , ! autoDownload ) }
checked = { autoDownload }
label = { _ _ ( 'Automatically download new content from my subscriptions' ) }
helper = { _ _ (
"The latest file from each of your subscriptions will be downloaded for quick access as soon as it's published."
) }
/> */ }
< fieldset - section >
< FormField
name = "max_connections"
type = "select"
label = { _ _ ( 'Max Connections' ) }
helper = { _ _ (
'For users with good bandwidth, try a higher value to improve streaming and download speeds. Low bandwidth users may benefit from a lower setting. Default is 4.'
) }
min = { 1 }
max = { 100 }
onChange = { this . onMaxConnectionsChange }
value = { daemonSettings . max _connections _per _download }
>
{ connectionOptions . map ( connectionOption => (
< option key = { connectionOption } value = { connectionOption } >
{ connectionOption }
< / option >
) ) }
< / FormField >
< / f i e l d s e t - s e c t i o n >
< SettingWalletServer / >
{ /* @endif */ }
< / React.Fragment >
}
/ >
) }
{ /* @if TARGET='app' */ }
{ /* Auto launch in a hidden state doesn't work on mac https://github.com/Teamwork/node-auto-launch/issues/81 */ }
{ ! IS _MAC && < Card title = { _ _ ( 'Startup Preferences' ) } actions = { < SettingAutoLaunch / > } / > }
2020-08-13 18:57:00 +02:00
< Card title = { _ _ ( 'Closing Preferences' ) } actions = { < SettingClosingBehavior / > } / >
2020-07-27 19:43:30 +02:00
{ /* @endif */ }
< / div >
) }
< / Page >
) ;
}
}
export default SettingsPage ;