Merge branch 'instant-purchase'

This commit is contained in:
Jeremy Kauffman 2017-09-22 18:34:39 -04:00
commit f7aec65912
7 changed files with 127 additions and 15 deletions

View file

@ -8,7 +8,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
## [Unreleased]
### Added
*
* Add setting to automatically purchase low-cost content without a confirmation dialog
*
### Changed

View file

@ -1,4 +1,5 @@
import * as types from "constants/action_types";
import * as settings from "constants/settings";
import lbry from "lbry";
import lbryio from "lbryio";
import lbryuri from "lbryuri";
@ -322,26 +323,55 @@ export function doPurchaseUri(uri) {
const downloadingByOutpoint = selectDownloadingByOutpoint(state);
const alreadyDownloading =
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
const costInfo = makeSelectCostInfoForUri(uri)(state);
const { cost } = costInfo;
if (
alreadyDownloading ||
(fileInfo && fileInfo.completed && fileInfo.written_bytes > 0)
) {
return;
function attemptPlay(cost, instantPurchaseMax = null) {
if (!instantPurchaseMax || cost > instantPurchaseMax) {
dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));
} else {
dispatch(doLoadVideo(uri));
}
}
// we already fully downloaded the file.
if (
cost === 0 ||
(fileInfo && (fileInfo.completed || fileInfo.download_directory))
) {
return dispatch(doLoadVideo(uri));
if (fileInfo && fileInfo.completed) {
// If written_bytes is false that means the user has deleted/moved the
// file manually on their file system, so we need to dispatch a
// doLoadVideo action to reconstruct the file from the blobs
if (!fileInfo.written_bytes) dispatch(doLoadVideo(uri));
return Promise.resolve();
}
// we are already downloading the file
if (alreadyDownloading) {
return Promise.resolve();
}
const costInfo = makeSelectCostInfoForUri(uri)(state);
const { cost } = costInfo;
if (cost > balance) {
return dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
return Promise.resolve();
}
if (
cost == 0 ||
!lbry.getClientSetting(settings.INSTANT_PURCHASE_ENABLED)
) {
attemptPlay(cost);
} else {
const instantPurchaseMax = lbry.getClientSetting(
settings.INSTANT_PURCHASE_MAX
);
if (instantPurchaseMax.currency == "LBC") {
attemptPlay(cost, instantPurchaseMax.amount);
} else {
// Need to convert currency of instant purchase maximum before trying to play
lbryio.getExchangeRates().then(({ lbc_usd }) => {
attemptPlay(cost, instantPurchaseMax.amount / lbc_usd);
});
}
}
return dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));

View file

@ -6,5 +6,7 @@ export const NEW_USER_ACKNOWLEDGED = "welcome_acknowledged";
export const LANGUAGE = "language";
export const SHOW_NSFW = "showNsfw";
export const SHOW_UNAVAILABLE = "showUnavailable";
export const INSTANT_PURCHASE_ENABLED = "instantPurchaseEnabled";
export const INSTANT_PURCHASE_MAX = "instantPurchaseMax";
export const THEME = "theme";
export const THEMES = "themes";

View file

@ -41,6 +41,9 @@ let lbry = {
language: "en",
theme: "light",
themes: [],
instantPurchaseMax: null,
instantPurchaseEnabled: false,
instantPurchaseMax: { currency: "LBC", amount: 0.1 },
},
};

View file

@ -21,6 +21,13 @@ const select = state => ({
daemonSettings: selectDaemonSettings(state),
showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state),
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
instantPurchaseEnabled: makeSelectClientSetting(
settings.INSTANT_PURCHASE_ENABLED
)(state),
instantPurchaseMax: makeSelectClientSetting(settings.INSTANT_PURCHASE_MAX)(
state
),
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
theme: makeSelectClientSetting(settings.THEME)(state),
themes: makeSelectClientSetting(settings.THEMES)(state),
language: selectCurrentLanguage(state),

View file

@ -13,6 +13,8 @@ class SettingsPage extends React.PureComponent {
super(props);
this.state = {
instantPurchaseEnabled: props.instantPurchaseEnabled,
instantPurchaseMax: props.instantPurchaseMax,
clearingCache: false,
};
}
@ -59,6 +61,22 @@ class SettingsPage extends React.PureComponent {
this.props.setClientSetting(settings.THEME, value);
}
oninstantPurchaseEnabledChange(enabled) {
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
this.setState({
instantPurchaseEnabled: enabled,
});
}
onInstantPurchaseMaxChange(newValue) {
this.props.setClientSetting(settings.INSTANT_PURCHASE_MAX, newValue);
this.setState({
instantPurchaseMax: newValue,
});
}
// onMaxUploadPrefChange(isLimited) {
// if (!isLimited) {
// this.setDaemonSetting("max_upload", 0.0);
@ -113,6 +131,8 @@ class SettingsPage extends React.PureComponent {
language,
languages,
showNsfw,
instantPurchaseEnabled,
instantPurchaseMax,
showUnavailable,
theme,
themes,
@ -167,9 +187,14 @@ class SettingsPage extends React.PureComponent {
</section>
<section className="card">
<div className="card__content">
<h3>{__("Max Purchase Price")}</h3>
<h3>{__("Purchase Settings")}</h3>
</div>
<div className="card__content">
<div className="form-row__label-row">
<label className="form-row__label">
{__("Max Purchase Price")}
</label>
</div>
<FormRow
type="radio"
name="max_key_fee"
@ -211,6 +236,47 @@ class SettingsPage extends React.PureComponent {
)}
</div>
</div>
<div className="card__content">
<div className="form-row__label-row">
<label className="form-row__label">
{__("Purchase Confirmations")}
</label>
</div>
<FormRow
type="radio"
name="instant_purchase_max"
checked={!this.state.instantPurchaseEnabled}
label={__("Ask for confirmation of all purchases")}
onClick={e => {
this.oninstantPurchaseEnabledChange(false);
}}
/>
<div className="form-row">
<FormField
type="radio"
name="instant_purchase_max"
checked={this.state.instantPurchaseEnabled}
label={
"Single-click purchasing of content less than" +
(this.state.instantPurchaseEnabled ? "" : "...")
}
onClick={e => {
this.oninstantPurchaseEnabledChange(true);
}}
/>
{this.state.instantPurchaseEnabled &&
<FormFieldPrice
min="0.1"
step="0.1"
onChange={val => this.onInstantPurchaseMaxChange(val)}
defaultValue={this.state.instantPurchaseMax}
/>}
</div>
<div className="form-field__helper">
When this option is chosen, LBRY won't ask you to confirm
downloads below the given price.
</div>
</div>
</section>
<section className="card">

View file

@ -6,6 +6,10 @@ import lbry from "lbry";
const reducers = {};
const defaultState = {
clientSettings: {
instantPurchaseEnabled: lbry.getClientSetting(
settings.INSTANT_PURCHASE_ENABLED
),
instantPurchaseMax: lbry.getClientSetting(settings.INSTANT_PURCHASE_MAX),
showNsfw: lbry.getClientSetting(settings.SHOW_NSFW),
showUnavailable: lbry.getClientSetting(settings.SHOW_UNAVAILABLE),
welcome_acknowledged: lbry.getClientSetting(settings.NEW_USER_ACKNOWLEDGED),