Add basics of Instant Purchase setting
Fix and simplify state management of Instant Purchas setting Add Instant Purchase check to Watch page Merge Max Purchase Price and Instant Purchase into one section Wording still not finalized. Add Instant Purchase setting names to constants Support USD for Instant Purchase On Settings page, use constants for new Instant Purchase settings Convert Instant Purchase Maximum setting into FormRow Update wording of Instant Purchase option and add helper text. Wording still not final. On Settings page, get Instant Purchase settings via selector Update CHANGELOG.md
This commit is contained in:
parent
27448499dd
commit
93b1ab8ac6
8 changed files with 125 additions and 15 deletions
|
@ -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
|
||||||
|
|
|
@ -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 }));
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,7 +187,7 @@ 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">
|
||||||
<FormRow
|
<FormRow
|
||||||
|
@ -211,6 +231,42 @@ class SettingsPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="card__content">
|
||||||
|
<FormField
|
||||||
|
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">
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -28,6 +28,14 @@ export const selectSettingsIsGenerous = createSelector(
|
||||||
//refactor me
|
//refactor me
|
||||||
export const selectShowNsfw = makeSelectClientSetting(settings.SHOW_NSFW);
|
export const selectShowNsfw = makeSelectClientSetting(settings.SHOW_NSFW);
|
||||||
|
|
||||||
|
export const selectInstantPurchaseEnabled = makeSelectClientSetting(
|
||||||
|
settings.INSTANT_PURCHASE_ENABLED
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectInstantPurchaseMax = makeSelectClientSetting(
|
||||||
|
settings.INSTANT_PURCHASE_MAX
|
||||||
|
);
|
||||||
|
|
||||||
export const selectLanguages = createSelector(
|
export const selectLanguages = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
state => state.languages || {}
|
state => state.languages || {}
|
||||||
|
|
Loading…
Reference in a new issue