3b23f09bed
remove previous changes,keep syncpref in wallet, change anon wallet pref key to local sync choices wip dont relocate syncenable setting bump no prefs on web unauth bugfix redux bump pull after sync change bump
520 lines
18 KiB
JavaScript
520 lines
18 KiB
JavaScript
// @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';
|
|
import SettingClosingBehavior from 'component/settingClosingBehavior';
|
|
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,
|
|
syncSettings: () => void,
|
|
enterSettings: () => void,
|
|
exitSettings: () => void,
|
|
};
|
|
|
|
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() {
|
|
const { isAuthenticated, ffmpegStatus, daemonSettings, findFFmpeg, enterSettings } = this.props;
|
|
|
|
// @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 });
|
|
}
|
|
});
|
|
}
|
|
enterSettings();
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
const { exitSettings } = this.props;
|
|
exitSettings();
|
|
}
|
|
|
|
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>
|
|
{/* @if TARGET='app' */}
|
|
<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>
|
|
{/* {__('Secure your local wallet data with a custom password.')}{' '}
|
|
<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>
|
|
</fieldset-section>
|
|
<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 />} />}
|
|
<Card title={__('Closing Preferences')} actions={<SettingClosingBehavior />} />
|
|
{/* @endif */}
|
|
</div>
|
|
)}
|
|
</Page>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default SettingsPage;
|