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] ## [Unreleased]
### Added ### Added
* * Add setting to automatically purchase low-cost content without a confirmation dialog
* *
### Changed ### Changed

View file

@ -1,4 +1,5 @@
import * as types from "constants/action_types"; import * as types from "constants/action_types";
import * as settings from "constants/settings";
import lbry from "lbry"; import lbry from "lbry";
import lbryio from "lbryio"; import lbryio from "lbryio";
import lbryuri from "lbryuri"; import lbryuri from "lbryuri";
@ -322,26 +323,55 @@ export function doPurchaseUri(uri) {
const downloadingByOutpoint = selectDownloadingByOutpoint(state); const downloadingByOutpoint = selectDownloadingByOutpoint(state);
const alreadyDownloading = const alreadyDownloading =
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
const costInfo = makeSelectCostInfoForUri(uri)(state);
const { cost } = costInfo;
if ( function attemptPlay(cost, instantPurchaseMax = null) {
alreadyDownloading || if (!instantPurchaseMax || cost > instantPurchaseMax) {
(fileInfo && fileInfo.completed && fileInfo.written_bytes > 0) dispatch(doOpenModal(modals.AFFIRM_PURCHASE, { uri }));
) { } else {
return; dispatch(doLoadVideo(uri));
}
} }
// we already fully downloaded the file. // we already fully downloaded the file.
if ( if (fileInfo && fileInfo.completed) {
cost === 0 || // If written_bytes is false that means the user has deleted/moved the
(fileInfo && (fileInfo.completed || fileInfo.download_directory)) // file manually on their file system, so we need to dispatch a
) { // doLoadVideo action to reconstruct the file from the blobs
return dispatch(doLoadVideo(uri)); 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) { 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 })); 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 LANGUAGE = "language";
export const SHOW_NSFW = "showNsfw"; export const SHOW_NSFW = "showNsfw";
export const SHOW_UNAVAILABLE = "showUnavailable"; export const SHOW_UNAVAILABLE = "showUnavailable";
export const INSTANT_PURCHASE_ENABLED = "instantPurchaseEnabled";
export const INSTANT_PURCHASE_MAX = "instantPurchaseMax";
export const THEME = "theme"; export const THEME = "theme";
export const THEMES = "themes"; export const THEMES = "themes";

View file

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

View file

@ -21,6 +21,13 @@ const select = state => ({
daemonSettings: selectDaemonSettings(state), daemonSettings: selectDaemonSettings(state),
showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state), showNsfw: makeSelectClientSetting(settings.SHOW_NSFW)(state),
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(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), theme: makeSelectClientSetting(settings.THEME)(state),
themes: makeSelectClientSetting(settings.THEMES)(state), themes: makeSelectClientSetting(settings.THEMES)(state),
language: selectCurrentLanguage(state), language: selectCurrentLanguage(state),

View file

@ -13,6 +13,8 @@ class SettingsPage extends React.PureComponent {
super(props); super(props);
this.state = { this.state = {
instantPurchaseEnabled: props.instantPurchaseEnabled,
instantPurchaseMax: props.instantPurchaseMax,
clearingCache: false, clearingCache: false,
}; };
} }
@ -59,6 +61,22 @@ class SettingsPage extends React.PureComponent {
this.props.setClientSetting(settings.THEME, value); 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) { // onMaxUploadPrefChange(isLimited) {
// if (!isLimited) { // if (!isLimited) {
// this.setDaemonSetting("max_upload", 0.0); // this.setDaemonSetting("max_upload", 0.0);
@ -113,6 +131,8 @@ class SettingsPage extends React.PureComponent {
language, language,
languages, languages,
showNsfw, showNsfw,
instantPurchaseEnabled,
instantPurchaseMax,
showUnavailable, showUnavailable,
theme, theme,
themes, themes,
@ -167,9 +187,14 @@ class SettingsPage extends React.PureComponent {
</section> </section>
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>{__("Max Purchase Price")}</h3> <h3>{__("Purchase Settings")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<div className="form-row__label-row">
<label className="form-row__label">
{__("Max Purchase Price")}
</label>
</div>
<FormRow <FormRow
type="radio" type="radio"
name="max_key_fee" name="max_key_fee"
@ -211,6 +236,47 @@ class SettingsPage extends React.PureComponent {
)} )}
</div> </div>
</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>
<section className="card"> <section className="card">

View file

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