From 93b1ab8ac642a90e35b24744b62f459e365d77ed Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Fri, 8 Sep 2017 01:03:37 -0400 Subject: [PATCH 1/2] 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 --- CHANGELOG.md | 2 +- ui/js/actions/content.js | 56 ++++++++++++++++++++++++++-------- ui/js/constants/settings.js | 2 ++ ui/js/lbry.js | 3 ++ ui/js/page/settings/index.js | 7 +++++ ui/js/page/settings/view.jsx | 58 +++++++++++++++++++++++++++++++++++- ui/js/reducers/settings.js | 4 +++ ui/js/selectors/settings.js | 8 +++++ 8 files changed, 125 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6ca0528..f22fa8404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index eb62506a2..e040eadfc 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -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 })); diff --git a/ui/js/constants/settings.js b/ui/js/constants/settings.js index a1a2e04e2..9346cfb70 100644 --- a/ui/js/constants/settings.js +++ b/ui/js/constants/settings.js @@ -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"; diff --git a/ui/js/lbry.js b/ui/js/lbry.js index 767d4479c..32770bcf1 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -41,6 +41,9 @@ let lbry = { language: "en", theme: "light", themes: [], + instantPurchaseMax: null, + instantPurchaseEnabled: false, + instantPurchaseMax: { currency: "LBC", amount: 0.1 }, }, }; diff --git a/ui/js/page/settings/index.js b/ui/js/page/settings/index.js index a44bf670c..c22cbdbe7 100644 --- a/ui/js/page/settings/index.js +++ b/ui/js/page/settings/index.js @@ -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), diff --git a/ui/js/page/settings/view.jsx b/ui/js/page/settings/view.jsx index c09c1be13..51370908a 100644 --- a/ui/js/page/settings/view.jsx +++ b/ui/js/page/settings/view.jsx @@ -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,7 +187,7 @@ class SettingsPage extends React.PureComponent {
-

{__("Max Purchase Price")}

+

{__("Purchase Settings")}

+
+ { + this.oninstantPurchaseEnabledChange(false); + }} + /> +
+ { + this.oninstantPurchaseEnabledChange(true); + }} + /> + {this.state.instantPurchaseEnabled && + this.onInstantPurchaseMaxChange(val)} + defaultValue={this.state.instantPurchaseMax} + />} +
+
+ When this option is chosen, LBRY won't ask you to confirm + downloads below the given price. +
+
diff --git a/ui/js/reducers/settings.js b/ui/js/reducers/settings.js index 2656c03fd..1c6834a91 100644 --- a/ui/js/reducers/settings.js +++ b/ui/js/reducers/settings.js @@ -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), diff --git a/ui/js/selectors/settings.js b/ui/js/selectors/settings.js index 5bf7f7f74..4b403d2c9 100644 --- a/ui/js/selectors/settings.js +++ b/ui/js/selectors/settings.js @@ -28,6 +28,14 @@ export const selectSettingsIsGenerous = createSelector( //refactor me 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( _selectState, state => state.languages || {} From b24b6e2e8e4b7ab7750f82776cb2f5cb641201be Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 22 Sep 2017 18:31:23 -0400 Subject: [PATCH 2/2] add labels, remove unused selectors --- ui/js/page/settings/view.jsx | 12 +++++++++++- ui/js/selectors/settings.js | 8 -------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ui/js/page/settings/view.jsx b/ui/js/page/settings/view.jsx index 51370908a..186abbb5c 100644 --- a/ui/js/page/settings/view.jsx +++ b/ui/js/page/settings/view.jsx @@ -190,6 +190,11 @@ class SettingsPage extends React.PureComponent {

{__("Purchase Settings")}

+
+ +
- + +
+ state.languages || {}