From d44d5806fd3a174392fd90cf3ccddec716290e8e Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 10 May 2017 04:05:55 -0400 Subject: [PATCH 01/18] Add setAsDefaultProtocolClient call for Windows --- app/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/main.js b/app/main.js index cac430513..e2035bcc2 100644 --- a/app/main.js +++ b/app/main.js @@ -315,6 +315,7 @@ function upgrade(event, installerPath) { ipcMain.on('upgrade', upgrade); +app.setAsDefaultProtocolClient('lbry'); if (process.platform == 'darwin') { app.on('open-url', (event, uri) => { if (!win) { From b189b31347c8e8359373cd7aba619e9f0168ca98 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 10 May 2017 04:30:26 -0400 Subject: [PATCH 02/18] Fix handling for URIs requested before window is open on Windows --- app/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/main.js b/app/main.js index e2035bcc2..4fcf6572e 100644 --- a/app/main.js +++ b/app/main.js @@ -327,5 +327,9 @@ if (process.platform == 'darwin') { }); } else if (process.argv.length >= 3) { // No open-url event on Win, but we can still handle URIs provided at launch time - win.webContents.send('open-uri-requested', process.argv[2]); + if (!win) { + openUri = process.argv[2]; + } else { + win.webContents.send('open-uri-requested', process.argv[2]); + } } From 856aa28db2a7fbc3e39121ac1c3cea8d33ab94de Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 10 May 2017 04:44:06 -0400 Subject: [PATCH 03/18] Convert to single-instance app - Prevents multiple windows from being opens at once - Allows for URI launching by capturing argv from second process --- app/main.js | 22 ++++++++++++++++++++++ lbry | 1 + lbryschema | 1 + lbryum | 1 + 4 files changed, 25 insertions(+) create mode 160000 lbry create mode 160000 lbryschema create mode 160000 lbryum diff --git a/app/main.js b/app/main.js index 4fcf6572e..aa0cde89f 100644 --- a/app/main.js +++ b/app/main.js @@ -177,6 +177,27 @@ function quitNow() { app.quit(); } +const isSecondaryInstance = app.makeSingleInstance((argv) => { + if (process.argv.length < 3) { + return; + } + + if (!win) { + openUri = argv[2]; + } else { + if (win.isMinimized()) { + win.restore(); + win.focus(); + } + + win.webContents.send('open-uri-requested', argv[2]); + } +}); + +if (isSecondaryInstance) { // We're not in the original process, so quit + quitNow(); + return; +} app.on('ready', function(){ launchDaemonIfNotRunning(); @@ -316,6 +337,7 @@ function upgrade(event, installerPath) { ipcMain.on('upgrade', upgrade); app.setAsDefaultProtocolClient('lbry'); + if (process.platform == 'darwin') { app.on('open-url', (event, uri) => { if (!win) { diff --git a/lbry b/lbry new file mode 160000 index 000000000..d99fc519b --- /dev/null +++ b/lbry @@ -0,0 +1 @@ +Subproject commit d99fc519b56ee910a44ef4af668b0770e9430d12 diff --git a/lbryschema b/lbryschema new file mode 160000 index 000000000..5c2441fa1 --- /dev/null +++ b/lbryschema @@ -0,0 +1 @@ +Subproject commit 5c2441fa13e39ba7280292519041e14ec696d753 diff --git a/lbryum b/lbryum new file mode 160000 index 000000000..950b95aa7 --- /dev/null +++ b/lbryum @@ -0,0 +1 @@ +Subproject commit 950b95aa7e45a2c15b269d807f6ff8e16bae4304 From 2b6528ca3ed1e193c5ee66809f6789c5c703039b Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 10 May 2017 21:27:57 -0400 Subject: [PATCH 04/18] Fix argv.length check in makeSingleInstance callback Also correct length of argv: with Electron, there's just the executable, not interpreter + filename. --- app/main.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/main.js b/app/main.js index aa0cde89f..e2e4c992a 100644 --- a/app/main.js +++ b/app/main.js @@ -178,19 +178,19 @@ function quitNow() { } const isSecondaryInstance = app.makeSingleInstance((argv) => { - if (process.argv.length < 3) { + if (argv.length < 2) { return; } if (!win) { - openUri = argv[2]; + openUri = argv[1]; } else { if (win.isMinimized()) { win.restore(); win.focus(); } - win.webContents.send('open-uri-requested', argv[2]); + win.webContents.send('open-uri-requested', argv[1]); } }); @@ -347,11 +347,11 @@ if (process.platform == 'darwin') { win.webContents.send('open-uri-requested', uri); } }); -} else if (process.argv.length >= 3) { +} else if (process.argv.length >= 2) { // No open-url event on Win, but we can still handle URIs provided at launch time if (!win) { - openUri = process.argv[2]; + openUri = process.argv[1]; } else { - win.webContents.send('open-uri-requested', process.argv[2]); + win.webContents.send('open-uri-requested', process.argv[1]); } } From df46c3f4e5733fd1c262910ceccf023af0f6290d Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Wed, 10 May 2017 23:40:07 -0400 Subject: [PATCH 05/18] Undo normalization that Windows does to URIs passed in from other apps --- app/main.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/app/main.js b/app/main.js index e2e4c992a..824ac8885 100644 --- a/app/main.js +++ b/app/main.js @@ -34,6 +34,22 @@ let readyToQuit = false; // send it to, it's cached in this variable. let openUri = null; +function denormalizeUri(uri) { + // Windows normalizes URIs when they're passed in from other apps. This tries + // to restore the original URI that was typed. + // - If the URI has no path, Windows adds a trailing slash. LBRY URIs + // can't have a slash with no path, so we just strip it off. + // - In a URI with a claim ID, like lbry://channel#claimid, Windows + // interprets the hash mark as an anchor and converts it to + // lbry://channel/#claimid. We remove the slash here as well. + + if (process.platform == 'win32') { + return uri.replace(/\/$/, '').replace('/#', '#'); + } else { + return uri; + } +} + function checkForNewVersion(callback) { function formatRc(ver) { // Adds dash if needed to make RC suffix semver friendly @@ -183,14 +199,14 @@ const isSecondaryInstance = app.makeSingleInstance((argv) => { } if (!win) { - openUri = argv[1]; + openUri = denormalizeUri(argv[1]); } else { if (win.isMinimized()) { win.restore(); win.focus(); } - win.webContents.send('open-uri-requested', argv[1]); + win.webContents.send('open-uri-requested', denormalizeUri(argv[1])); } }); @@ -348,10 +364,9 @@ if (process.platform == 'darwin') { } }); } else if (process.argv.length >= 2) { - // No open-url event on Win, but we can still handle URIs provided at launch time if (!win) { - openUri = process.argv[1]; + openUri = denormalizeUri(process.argv[1]); } else { - win.webContents.send('open-uri-requested', process.argv[1]); + win.webContents.send('open-uri-requested', denormalizeUri(process.argv[1])); } } From d888707d5605293568e2f3018a63c4bbb372df4e Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Thu, 11 May 2017 00:03:39 -0400 Subject: [PATCH 06/18] Tweak logic in makeSingleInstance callback --- app/main.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/main.js b/app/main.js index 824ac8885..3328b928d 100644 --- a/app/main.js +++ b/app/main.js @@ -194,19 +194,17 @@ function quitNow() { } const isSecondaryInstance = app.makeSingleInstance((argv) => { - if (argv.length < 2) { - return; - } - - if (!win) { - openUri = denormalizeUri(argv[1]); - } else { + if (win) { if (win.isMinimized()) { win.restore(); - win.focus(); } + win.focus(); - win.webContents.send('open-uri-requested', denormalizeUri(argv[1])); + if (argv.length >= 2) { + win.webContents.send('open-uri-requested', denormalizeUri(argv[1])); + } + } else if (argv.length >= 2) { + openUri = denormalizeUri(argv[1]); } }); From 980a50926067b1f3fca32bd33f878bf6e542d8bd Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Thu, 11 May 2017 03:30:23 -0400 Subject: [PATCH 07/18] Disable single instance app on Linux for now (Electron bug) On Linux, app.makeSingleInstance is always returning true (i.e. "this is not the original process"). --- app/main.js | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/main.js b/app/main.js index 3328b928d..14e5b7f90 100644 --- a/app/main.js +++ b/app/main.js @@ -193,24 +193,28 @@ function quitNow() { app.quit(); } -const isSecondaryInstance = app.makeSingleInstance((argv) => { - if (win) { - if (win.isMinimized()) { - win.restore(); - } - win.focus(); +if (process.platform != 'linux') { + // On Linux, this is always returning true due to an Electron bug, + // so for now we just don't support single-instance apps on Linux. + const isSecondaryInstance = app.makeSingleInstance((argv) => { + if (win) { + if (win.isMinimized()) { + win.restore(); + } + win.focus(); - if (argv.length >= 2) { - win.webContents.send('open-uri-requested', denormalizeUri(argv[1])); + if (argv.length >= 2) { + win.webContents.send('open-uri-requested', denormalizeUri(argv[1])); + } + } else if (argv.length >= 2) { + openUri = denormalizeUri(argv[1]); } - } else if (argv.length >= 2) { - openUri = denormalizeUri(argv[1]); + }); + + if (isSecondaryInstance) { // We're not in the original process, so quit + quitNow(); + return; } -}); - -if (isSecondaryInstance) { // We're not in the original process, so quit - quitNow(); - return; } app.on('ready', function(){ From 32fd2c2c7a8f1e0397584a1760297bd74487a945 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Thu, 11 May 2017 03:41:35 -0400 Subject: [PATCH 08/18] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b6aa8859..5ff185868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Web UI version numbers should always match the corresponding version of LBRY App * Handle more of price calculations at the daemon layer to improve page load time * Add special support for building channel claims in lbryuri module * Enable windows code signing of binary + * Support for opening LBRY URIs from links in other apps ### Changed @@ -55,6 +56,7 @@ Web UI version numbers should always match the corresponding version of LBRY App ### Fixed * Fix Watch page and progress bars for new API changes + * On Windows, prevent opening multiple LBRY instances (launching LBRY again just focuses the current instance) From 5605b10f542dca722eafb202f1633440d0d0ba4e Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 12 May 2017 13:14:06 -0400 Subject: [PATCH 09/18] more bug fixes and bugs --- ui/js/actions/content.js | 2 - ui/js/actions/cost_info.js | 2 +- ui/js/component/filePrice/index.js | 4 + ui/js/component/filePrice/view.jsx | 44 ++++++-- ui/js/component/video/view.jsx | 5 +- ui/js/lbryio.js | 5 +- ui/js/page/filePage/index.js | 4 + ui/js/page/filePage/view.jsx | 162 ++++++++++++++++------------- ui/js/page/showPage/view.jsx | 2 +- ui/js/selectors/cost_info.js | 2 +- ui/package.json | 1 - ui/scss/_mediaelement.scss | 16 --- ui/scss/all.scss | 2 - ui/scss/page/_watch.scss | 48 --------- 14 files changed, 142 insertions(+), 157 deletions(-) delete mode 100644 ui/scss/_mediaelement.scss delete mode 100644 ui/scss/page/_watch.scss diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index cc64d8d9a..5c0e288fd 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -47,8 +47,6 @@ export function doResolveUri(uri) { certificate, } }) - - dispatch(doFetchCostInfoForUri(uri)) }) } } diff --git a/ui/js/actions/cost_info.js b/ui/js/actions/cost_info.js index 5d28fb42c..5a6a66604 100644 --- a/ui/js/actions/cost_info.js +++ b/ui/js/actions/cost_info.js @@ -26,7 +26,7 @@ export function doFetchCostInfoForUri(uri) { type: types.FETCH_COST_INFO_COMPLETED, data: { uri, - costInfo: {} + costInfo: null } }) }) diff --git a/ui/js/component/filePrice/index.js b/ui/js/component/filePrice/index.js index c5a9497d0..b2271e493 100644 --- a/ui/js/component/filePrice/index.js +++ b/ui/js/component/filePrice/index.js @@ -2,6 +2,9 @@ import React from 'react' import { connect, } from 'react-redux' +import { + doFetchCostInfoForUri, +} from 'actions/cost_info' import { makeSelectCostInfoForUri, } from 'selectors/cost_info' @@ -17,6 +20,7 @@ const makeSelect = () => { } const perform = (dispatch) => ({ + fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)) }) export default connect(makeSelect, perform)(FilePrice) diff --git a/ui/js/component/filePrice/view.jsx b/ui/js/component/filePrice/view.jsx index 17b830bf2..4edc3a3e7 100644 --- a/ui/js/component/filePrice/view.jsx +++ b/ui/js/component/filePrice/view.jsx @@ -3,19 +3,41 @@ import { CreditAmount, } from 'component/common' -const FilePrice = (props) => { - const { - costInfo, - look = 'indicator', - } = props - - const isEstimate = costInfo ? !costInfo.includesData : null - - if (!costInfo) { - return ???; +class FilePrice extends React.Component{ + componentWillMount() { + this.fetchCost(this.props) } - return + componentWillReceiveProps(nextProps) { + this.fetchCost(nextProps) + } + + fetchCost(props) { + const { + costInfo, + fetchCostInfo, + uri + } = props + + if (costInfo === undefined) { + fetchCostInfo(uri) + } + } + + render() { + const { + costInfo, + look = 'indicator', + } = this.props + + const isEstimate = costInfo ? !costInfo.includesData : null + + if (!costInfo) { + return ???; + } + + return + } } export default FilePrice diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index 5485f1a48..e19e6b2a4 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -32,9 +32,12 @@ class WatchLink extends React.Component { fileInfo, } = this.props + console.log('watch link render') + console.log(fileInfo) + return (
EXCHANGE_RATE_TIMEOUT) { + + } return new Promise((resolve, reject) => { - const cached = getSession('exchangeRateCache'); if (!cached || Date.now() - cached.time > EXCHANGE_RATE_TIMEOUT) { lbryio.call('lbc', 'exchange_rate', {}, 'get', true).then(({lbc_usd, lbc_btc, btc_usd}) => { const rates = {lbc_usd, lbc_btc, btc_usd}; diff --git a/ui/js/page/filePage/index.js b/ui/js/page/filePage/index.js index a083bdf9c..3d0ba7665 100644 --- a/ui/js/page/filePage/index.js +++ b/ui/js/page/filePage/index.js @@ -2,6 +2,9 @@ import React from 'react' import { connect } from 'react-redux' +import { + doFetchCurrentUriFileInfo +} from 'actions/file_info' import { selectCurrentUri, } from 'selectors/app' @@ -26,6 +29,7 @@ const select = (state) => ({ }) const perform = (dispatch) => ({ + fetchFileInfo: () => dispatch(doFetchCurrentUriFileInfo()) }) export default connect(select, perform)(FilePage) diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index 30938d635..d5a29d7a9 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -45,87 +45,105 @@ const FormatItem = (props) => { ) } -const FilePage = (props) => { - const { - claim, - navigate, - claim: { - txid, - nout, - has_signature: hasSignature, - signature_is_valid: signatureIsValid, - value, - value: { - stream, - stream: { - metadata, - source, - metadata: { - title, - } = {}, - source: { - contentType, +class FilePage extends React.Component{ + + componentWillMount() { + this.fetchFileInfo(this.props) + } + + componentWillReceiveProps(nextProps) { + this.fetchFileInfo(nextProps) + } + + fetchFileInfo(props) { + if (!props.fileInfo) { + console.log('fetch file info') + props.fetchFileInfo() + } + } + + render() { + const { + claim, + navigate, + claim: { + txid, + nout, + has_signature: hasSignature, + signature_is_valid: signatureIsValid, + value, + value: { + stream, + stream: { + metadata, + source, + metadata: { + title, + } = {}, + source: { + contentType, + } = {}, } = {}, } = {}, + }, + uri, + isDownloaded, + fileInfo, + costInfo, + costInfo: { + cost, + includesData: costIncludesData, } = {}, - }, - uri, - isDownloaded, - fileInfo, - costInfo, - costInfo: { - cost, - includesData: costIncludesData, - } = {}, - } = props + } = this.props - const outpoint = txid + ':' + nout; - const uriLookupComplete = !!claim && Object.keys(claim).length + const outpoint = txid + ':' + nout; + const uriLookupComplete = !!claim && Object.keys(claim).length - const channelUriObj = lbryuri.parse(uri) - delete channelUriObj.path; - delete channelUriObj.contentName; - const channelUri = signatureIsValid && hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null; - const uriIndicator = + const channelUriObj = lbryuri.parse(uri) + delete channelUriObj.path; + delete channelUriObj.contentName; + const channelUri = signatureIsValid && hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null; + const uriIndicator = - //

This location is not yet in use. { ' ' } navigate('/publish')} label="Put something here" />.

+ //

This location is not yet in use. { ' ' } navigate('/publish')} label="Put something here" />.

- return ( -
-
- { contentType && contentType.startsWith('video/') ? -
-
-
-
- {isDownloaded === false - ? - : null} -

{title}

-
- { channelUri ? - {uriIndicator} : - uriIndicator} -
-
-
+ return ( +
+
+ { contentType && contentType.startsWith('video/') ? +
+
+
+
+ {isDownloaded === false + ? + : null}

{title}

+
+ { channelUri ? + {uriIndicator} : + uriIndicator} +
+
+
+
+
+ {metadata.description} +
-
- {metadata.description} -
-
- { metadata ? + { metadata ? +
+ +
: '' }
- -
: '' } -
- -
-
-
- ) + +
+ + + ) + } } export default FilePage; \ No newline at end of file diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx index 7e84d3d30..bdc4f7a81 100644 --- a/ui/js/page/showPage/view.jsx +++ b/ui/js/page/showPage/view.jsx @@ -41,7 +41,7 @@ class ShowPage extends React.Component{

{uri}

- : +
; } diff --git a/ui/js/selectors/cost_info.js b/ui/js/selectors/cost_info.js index f48fa3438..da55c89af 100644 --- a/ui/js/selectors/cost_info.js +++ b/ui/js/selectors/cost_info.js @@ -14,7 +14,7 @@ export const selectAllCostInfoByUri = createSelector( export const selectCurrentUriCostInfo = createSelector( selectCurrentUri, selectAllCostInfoByUri, - (uri, byUri) => byUri[uri] || {} + (uri, byUri) => byUri[uri] ) export const selectFetchingCostInfo = createSelector( diff --git a/ui/package.json b/ui/package.json index e73d866f6..72d7bdde1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -22,7 +22,6 @@ "babel-cli": "^6.11.4", "babel-preset-es2015": "^6.13.2", "babel-preset-react": "^6.11.1", - "mediaelement": "^2.23.4", "node-sass": "^3.8.0", "plyr": "^2.0.12", "rc-progress": "^2.0.6", diff --git a/ui/scss/_mediaelement.scss b/ui/scss/_mediaelement.scss deleted file mode 100644 index 44488808f..000000000 --- a/ui/scss/_mediaelement.scss +++ /dev/null @@ -1,16 +0,0 @@ -@import "global"; - -.mejs-container, .mejs-overlay, .mejs-mediaelement { - width: 100%; - height: 100%; -} - -.me-plugin { - width: 100%; - height: 100%; - - > embed { - width: 100%; - height: 100%; - } -} \ No newline at end of file diff --git a/ui/scss/all.scss b/ui/scss/all.scss index 7c87a5fbb..e69354bd0 100644 --- a/ui/scss/all.scss +++ b/ui/scss/all.scss @@ -1,6 +1,5 @@ @import "_reset"; @import "_icons"; -@import "_mediaelement"; @import "_gui"; @import "component/_table"; @import "component/_button.scss"; @@ -19,6 +18,5 @@ @import "component/_snack-bar.scss"; @import "component/_video.scss"; @import "page/_developer.scss"; -@import "page/_watch.scss"; @import "page/_reward.scss"; @import "page/_show.scss"; diff --git a/ui/scss/page/_watch.scss b/ui/scss/page/_watch.scss deleted file mode 100644 index 6ed5459ae..000000000 --- a/ui/scss/page/_watch.scss +++ /dev/null @@ -1,48 +0,0 @@ - -.video__overlay { - position: absolute; - top: 0px; - left: 0px; - color: #fff; - z-index: 1; -} - -.video__back { - margin-top: 30px; - margin-left: 50px; - display: flex; - flex-direction: row; - align-items: center; -} - -.video__back-link { - font-size: 50px; -} - -.video__back-label { - opacity: 0.5; - transition: opacity 100ms ease-in; -} - -.video__back-link:hover + .video__back-label { - opacity: 1; -} - -$video-back-background: #333; -$video-back-size: 20px; - -.video__back-label-arrow { - color: $video-back-background; - font-size: $video-back-size; -} - -.video__back-label-content { - display: inline-block; - margin-left: -2px; - font-size: $video-back-size; - padding: $spacing-vertical / 2; - border-radius: 3px; - background-color: $video-back-background; - color: #fff; - pointer-events: none; -} From 950f3183cfe287c8139787c130e7ed9f71f340c7 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 12 May 2017 14:36:44 -0400 Subject: [PATCH 10/18] more bug fixes + optimizations --- ui/js/component/fileTile/view.jsx | 2 +- ui/js/component/video/view.jsx | 3 --- ui/js/component/wunderbar/view.jsx | 16 ++++++++++++---- ui/js/lbryio.js | 24 +++++++++--------------- ui/js/page/filePage/view.jsx | 1 - 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/ui/js/component/fileTile/view.jsx b/ui/js/component/fileTile/view.jsx index 455e59d5a..a2b404a5d 100644 --- a/ui/js/component/fileTile/view.jsx +++ b/ui/js/component/fileTile/view.jsx @@ -92,7 +92,7 @@ class FileTile extends React.Component { let description = "" if (isClaimed) { - description = metadata.description + description = metadata && metadata.description } else if (isResolvingUri) { description = "Loading..." } else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) { diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index e19e6b2a4..265c31a9f 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -32,9 +32,6 @@ class WatchLink extends React.Component { fileInfo, } = this.props - console.log('watch link render') - console.log(fileInfo) - return (
EXCHANGE_RATE_TIMEOUT) { - - } - return new Promise((resolve, reject) => { - if (!cached || Date.now() - cached.time > EXCHANGE_RATE_TIMEOUT) { + if (!lbryio._exchangeLastFetched || Date.now() - lbryio._exchangeLastFetched > EXCHANGE_RATE_TIMEOUT) { + lbryio._exchangePromise = new Promise((resolve, reject) => { lbryio.call('lbc', 'exchange_rate', {}, 'get', true).then(({lbc_usd, lbc_btc, btc_usd}) => { const rates = {lbc_usd, lbc_btc, btc_usd}; - setSession('exchangeRateCache', { - rates: rates, - time: Date.now(), - }); resolve(rates); - }); - } else { - resolve(cached.rates); - } - }); + }).catch(reject); + }); + lbryio._exchangeLastFetched = Date.now(); + } + return lbryio._exchangePromise; } lbryio.call = function(resource, action, params={}, method='get', evenIfDisabled=false) { // evenIfDisabled is just for development, when we may have some calls working and some not diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index d5a29d7a9..493695c4c 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -57,7 +57,6 @@ class FilePage extends React.Component{ fetchFileInfo(props) { if (!props.fileInfo) { - console.log('fetch file info') props.fetchFileInfo() } } From c823ccd056d15c181c7bf336e9266d65cda1ae31 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 12 May 2017 16:49:15 -0400 Subject: [PATCH 11/18] fix infinite resolve, add valid uri check --- ui/js/component/fileTile/view.jsx | 6 +++++- ui/js/lbryuri.js | 20 ++++++++++++++++++++ ui/js/page/search/view.jsx | 3 +-- ui/js/page/showPage/view.jsx | 9 +++++---- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/ui/js/component/fileTile/view.jsx b/ui/js/component/fileTile/view.jsx index a2b404a5d..81fac9fa2 100644 --- a/ui/js/component/fileTile/view.jsx +++ b/ui/js/component/fileTile/view.jsx @@ -86,6 +86,7 @@ class FileTile extends React.Component { const uri = lbryuri.normalize(this.props.uri); const isClaimed = !!claim; + const isClaimable = lbryuri.isClaimable(uri) const title = isClaimed && metadata && metadata.title ? metadata.title : uri; const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw; let onClick = () => navigate('/show', { uri }) @@ -97,7 +98,10 @@ class FileTile extends React.Component { description = "Loading..." } else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) { onClick = () => navigate('/publish') - description = This location is unclaimed - put something here! + description = + This location is unused. { ' ' } + { isClaimable && Put something here! } + } else if (showEmpty === FileTile.SHOW_EMPTY_PENDING) { description = This file is pending confirmation. } diff --git a/ui/js/lbryuri.js b/ui/js/lbryuri.js index 2712b812a..637a2fd67 100644 --- a/ui/js/lbryuri.js +++ b/ui/js/lbryuri.js @@ -165,5 +165,25 @@ lbryuri.normalize= function(uri) { return lbryuri.build({name, path, claimSequence, bidPosition, claimId}); } +lbryuri.isValid = function(uri) { + let parts + try { + parts = lbryuri.parse(lbryuri.normalize(uri)) + } catch (error) { + return false; + } + return parts && parts.name; +} + +lbryuri.isClaimable = function(uri) { + let parts + try { + parts = lbryuri.parse(lbryuri.normalize(uri)) + } catch (error) { + return false; + } + return parts && parts.name && !parts.claimId && !parts.bidPosition && !parts.claimSequence && !parts.isChannel && !parts.path; +} + window.lbryuri = lbryuri; export default lbryuri; diff --git a/ui/js/page/search/view.jsx b/ui/js/page/search/view.jsx index 30f9b2aee..8328434fc 100644 --- a/ui/js/page/search/view.jsx +++ b/ui/js/page/search/view.jsx @@ -8,14 +8,13 @@ import {BusyMessage} from 'component/common.js'; class SearchPage extends React.Component{ render() { - const isValidUri = (query) => true //FIXME const { query, } = this.props return (
- { isValidUri(query) ? + { lbryuri.isValid(query) ?

Exact URL

{uri}

- + { isResolvingUri && } + { claim === null && There's nothing at this location. }
-

; + } else if (claim && claim.whatever) { innerContent = "channel" From 0fad6864ec23566663be84266ea994bd384b0123 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 12 May 2017 18:50:51 -0400 Subject: [PATCH 12/18] let improvements and breaking continue --- ui/js/actions/content.js | 52 +++++++++++++++++++++------ ui/js/component/filePrice/view.jsx | 2 +- ui/js/constants/action_types.js | 2 ++ ui/js/lbry.js | 9 +++-- ui/js/page/channel/index.js | 14 ++++++-- ui/js/page/channel/view.jsx | 56 +++++++++++++++++++++--------- ui/js/page/filePage/view.jsx | 10 +++--- ui/js/page/showPage/index.js | 2 ++ ui/js/page/showPage/view.jsx | 6 ++-- ui/js/reducers/certificates.js | 27 -------------- ui/js/reducers/claims.js | 38 ++++++++++++++++++-- ui/js/selectors/app.js | 5 --- ui/js/selectors/claims.js | 24 ++++++++++++- ui/js/store.js | 2 -- 14 files changed, 170 insertions(+), 79 deletions(-) delete mode 100644 ui/js/reducers/certificates.js diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 5c0e288fd..297ae221c 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -22,9 +22,6 @@ import { import { doOpenModal, } from 'actions/app' -import { - doFetchCostInfoForUri, -} from 'actions/cost_info' export function doResolveUri(uri) { return function(dispatch, getState) { @@ -47,6 +44,15 @@ export function doResolveUri(uri) { certificate, } }) + }).catch(() => { + dispatch({ + type: types.RESOLVE_URI_COMPLETED, + data: { + uri, + claim: null, + certificate: null, + } + }) }) } } @@ -114,6 +120,8 @@ export function doFetchPublishedContent() { export function doFetchFeaturedUris() { return function(dispatch, getState) { + return + const state = getState() dispatch({ @@ -198,13 +206,6 @@ export function doUpdateLoadStatus(uri, outpoint) { } } -export function doPlayVideo(uri) { - return { - type: types.PLAY_VIDEO_STARTED, - data: { uri } - } -} - export function doDownloadFile(uri, streamInfo) { return function(dispatch, getState) { const state = getState() @@ -300,3 +301,34 @@ export function doWatchVideo() { return Promise.resolve() } } + +export function doFetchChannelClaims(uri) { + return function(dispatch, getState) { + dispatch({ + type: types.FETCH_CHANNEL_CLAIMS_STARTED, + data: { uri } + }) + + lbry.resolve({ uri }).then((resolutionInfo) => { + const { + claims_in_channel, + } = resolutionInfo ? resolutionInfo : { claims_in_channel: [] } + + dispatch({ + type: types.FETCH_CHANNEL_CLAIMS_STARTED, + data: { + uri, + claims: claims_in_channel + } + }) + }).catch(() => { + dispatch({ + type: types.FETCH_CHANNEL_CLAIMS_COMPLETED, + data: { + uri, + claims: [] + } + }) + }) + } +} \ No newline at end of file diff --git a/ui/js/component/filePrice/view.jsx b/ui/js/component/filePrice/view.jsx index 4edc3a3e7..56174c8a2 100644 --- a/ui/js/component/filePrice/view.jsx +++ b/ui/js/component/filePrice/view.jsx @@ -4,7 +4,7 @@ import { } from 'component/common' class FilePrice extends React.Component{ - componentWillMount() { + componentDidMount() { this.fetchCost(this.props) } diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index 70a75e69f..942d65cdd 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -35,6 +35,8 @@ export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED' export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED' export const RESOLVE_URI_STARTED = 'RESOLVE_URI_STARTED' export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED' +export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED' +export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED' export const FETCH_DOWNLOADED_CONTENT_STARTED = 'FETCH_DOWNLOADED_CONTENT_STARTED' export const FETCH_DOWNLOADED_CONTENT_COMPLETED = 'FETCH_DOWNLOADED_CONTENT_COMPLETED' export const FETCH_PUBLISHED_CONTENT_STARTED = 'FETCH_PUBLISHED_CONTENT_STARTED' diff --git a/ui/js/lbry.js b/ui/js/lbry.js index 5dacc389d..d03ceea55 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -640,8 +640,9 @@ lbry.claim_list_mine = function(params={}) { } const claimCacheKey = 'resolve_claim_cache'; -lbry._claimCache = getLocal(claimCacheKey, {}); +lbry._claimCache = getSession(claimCacheKey, {}); lbry.resolve = function(params={}) { + console.log('resolve: ' + params.uri); return new Promise((resolve, reject) => { if (!params.uri) { throw "Resolve has hacked cache on top of it that requires a URI" @@ -650,8 +651,10 @@ lbry.resolve = function(params={}) { resolve(lbry._claimCache[params.uri]); } else { lbry.call('resolve', params, function(data) { - lbry._claimCache[params.uri] = data; - setLocal(claimCacheKey, lbry._claimCache) + if (data !== undefined) { + lbry._claimCache[params.uri] = data; + } + setSession(claimCacheKey, lbry._claimCache) resolve(data) }, reject) } diff --git a/ui/js/page/channel/index.js b/ui/js/page/channel/index.js index 50100b244..dbb3fa875 100644 --- a/ui/js/page/channel/index.js +++ b/ui/js/page/channel/index.js @@ -3,15 +3,25 @@ import { connect } from 'react-redux' import { - selectCurrentUriTitle, + doFetchChannelClaims +} from 'actions/content' +import { + selectCurrentUri, } from 'selectors/app' +import { + selectCurrentUriClaim, + selectCurrentUriClaims, +} from 'selectors/claims' import ChannelPage from './view' const select = (state) => ({ - title: selectCurrentUriTitle(state) + uri: selectCurrentUri(state), + claim: selectCurrentUriClaim(state), + claims: selectCurrentUriClaims(state) }) const perform = (dispatch) => ({ + fetchClaims: (uri) => dispatch(doFetchChannelClaims(uri)) }) export default connect(select, perform)(ChannelPage) diff --git a/ui/js/page/channel/view.jsx b/ui/js/page/channel/view.jsx index 587c7237e..1542f14af 100644 --- a/ui/js/page/channel/view.jsx +++ b/ui/js/page/channel/view.jsx @@ -1,22 +1,46 @@ import React from 'react'; -const ChannelPage = (props) => { - const { - title - } = props +class ChannelPage extends React.Component{ + componentDidMount() { + this.fetchClaims(this.props) + } - return
-
-
-

{title}

-
-
-

- This channel page is a stub. -

-
-
-
+ componentWillReceiveProps(nextProps) { + this.fetchClaims(nextProps) + } + + fetchClaims(props) { + if (props.claims === undefined) { + props.fetchClaims(props.uri) + } + } + + render() { + const { + claims, + claim, + uri + } = this.props + + console.log(claims); + return
+
+
+

{uri}

+
+
+

+ This channel page is a stub. +

+
+
+
+
+ {claims} +
+
+
+ } } export default ChannelPage; diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index 493695c4c..f2b9ab3c8 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -47,7 +47,7 @@ const FormatItem = (props) => { class FilePage extends React.Component{ - componentWillMount() { + componentDidMount() { this.fetchFileInfo(this.props) } @@ -56,7 +56,7 @@ class FilePage extends React.Component{ } fetchFileInfo(props) { - if (!props.fileInfo) { + if (props.fileInfo === undefined) { props.fetchFileInfo() } } @@ -104,14 +104,12 @@ class FilePage extends React.Component{ const channelUri = signatureIsValid && hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null; const uriIndicator = - //

This location is not yet in use. { ' ' } navigate('/publish')} label="Put something here" />.

- return (
{ contentType && contentType.startsWith('video/') ?
@@ -128,7 +126,7 @@ class FilePage extends React.Component{
- {metadata.description} + {metadata && metadata.description}
{ metadata ? diff --git a/ui/js/page/showPage/index.js b/ui/js/page/showPage/index.js index bbaba13f6..1145b03c7 100644 --- a/ui/js/page/showPage/index.js +++ b/ui/js/page/showPage/index.js @@ -10,6 +10,7 @@ import { } from 'selectors/app' import { selectCurrentUriClaim, + selectCurrentUriChannelClaim, } from 'selectors/claims' import { selectCurrentUriIsResolving, @@ -17,6 +18,7 @@ import { import ShowPage from './view' const select = (state, props) => ({ + channelClaim: selectCurrentUriChannelClaim(state), claim: selectCurrentUriClaim(state), uri: selectCurrentUri(state), isResolvingUri: selectCurrentUriIsResolving(state) diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx index f12d55ac1..3d85a10b4 100644 --- a/ui/js/page/showPage/view.jsx +++ b/ui/js/page/showPage/view.jsx @@ -28,6 +28,7 @@ class ShowPage extends React.Component{ render() { const { + channelClaim, claim, uri, isResolvingUri, @@ -46,9 +47,8 @@ class ShowPage extends React.Component{ } - else if (claim && claim.whatever) { - innerContent = "channel" - // innerContent = + else if (channelClaim && claim && channelClaim.txid && channelClaim.txid === claim.txid) { + innerContent = } else if (claim) { innerContent = diff --git a/ui/js/reducers/certificates.js b/ui/js/reducers/certificates.js deleted file mode 100644 index ebeaed986..000000000 --- a/ui/js/reducers/certificates.js +++ /dev/null @@ -1,27 +0,0 @@ -import * as types from 'constants/action_types' - -const reducers = {} -const defaultState = { -} - -reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { - const { - uri, - certificate, - } = action.data - if (!certificate) return state - - const newByUri = Object.assign({}, state.byUri) - - newByUri[uri] = certificate - return Object.assign({}, state, { - byUri: newByUri, - }) -} - - -export default function reducer(state = defaultState, action) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index c758052bc..73b1c34a0 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -8,13 +8,45 @@ const defaultState = { reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { const { uri, + certificate, claim, } = action.data - const newByUri = Object.assign({}, state.byUri) - newByUri[uri] = claim + const newClaims = Object.assign({}, state.claimsByUri) + const newChannelClaims = Object.assign({}, state.channelClaimsByUri) + + if (claim !== undefined) { + newClaims[uri] = claim + } + + //This needs a sanity boost... + if (certificate !== undefined) { + newChannelClaims[uri] = certificate + if (claim === undefined) { + newClaims[uri] = certificate + } + } + return Object.assign({}, state, { - byUri: newByUri, + claimsByUri: newClaims, + channelClaimsByUri: newChannelClaims + }) +} + +reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) { + const { + uri, + claims + } = action.data + + const newClaims = Object.assign({}, state.claimsByChannel) + + if (claims !== undefined) { + newClaims[uri] = claims + } + + return Object.assign({}, state, { + claimsByChannel: newClaims }) } diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js index 7692adae7..a1d9ce400 100644 --- a/ui/js/selectors/app.js +++ b/ui/js/selectors/app.js @@ -43,11 +43,6 @@ export const selectCurrentUri = createSelector( } ) -export const selectCurrentUriTitle = createSelector( - _selectState, - (state) => "fix me" -) - export const selectPageTitle = createSelector( selectCurrentPage, selectCurrentUri, diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index a755eea18..fc6593606 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -10,7 +10,7 @@ export const _selectState = state => state.claims || {} export const selectClaimsByUri = createSelector( _selectState, - (state) => state.byUri || {} + (state) => state.claimsByUri || {} ) export const selectCurrentUriClaim = createSelector( @@ -19,6 +19,17 @@ export const selectCurrentUriClaim = createSelector( (uri, byUri) => byUri[uri] ) +export const selectChannelClaimsByUri = createSelector( + _selectState, + (state) => state.channelClaimsByUri || {} +) + +export const selectCurrentUriChannelClaim = createSelector( + selectCurrentUri, + selectChannelClaimsByUri, + (uri, byUri) => byUri[uri] +) + export const selectCurrentUriClaimOutpoint = createSelector( selectCurrentUriClaim, (claim) => { @@ -26,6 +37,17 @@ export const selectCurrentUriClaimOutpoint = createSelector( } ) +export const selectClaimsByChannel = createSelector( + _selectState, + (state) => state.claimsByChannel || {} +) + +export const selectCurrentUriClaims = createSelector( + selectCurrentUri, + selectClaimsByChannel, + (uri, byChannel) => byChannel[uri] +) + const selectClaimForUri = (state, props) => { const uri = lbryuri.normalize(props.uri) return selectClaimsByUri(state)[uri] diff --git a/ui/js/store.js b/ui/js/store.js index 462c6a5d0..7ab606258 100644 --- a/ui/js/store.js +++ b/ui/js/store.js @@ -7,7 +7,6 @@ import { } from 'redux-logger' import appReducer from 'reducers/app'; import availabilityReducer from 'reducers/availability' -import certificatesReducer from 'reducers/certificates' import claimsReducer from 'reducers/claims' import contentReducer from 'reducers/content'; import costInfoReducer from 'reducers/cost_info' @@ -49,7 +48,6 @@ function enableBatching(reducer) { const reducers = redux.combineReducers({ app: appReducer, availability: availabilityReducer, - certificates: certificatesReducer, claims: claimsReducer, fileInfo: fileInfoReducer, content: contentReducer, From 6783bcdfeb6edf5f84de21e30a43c45c6d6a6f1a Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Sun, 14 May 2017 23:50:59 -0400 Subject: [PATCH 13/18] i'm making things better... right? --- ui/js/actions/app.js | 1 - ui/js/actions/availability.js | 52 ++++----- ui/js/actions/content.js | 36 ++----- ui/js/actions/cost_info.js | 3 - ui/js/actions/file_info.js | 46 ++++---- ui/js/component/app/index.js | 11 -- ui/js/component/app/view.jsx | 1 - ui/js/component/fileActions/index.js | 23 ++-- ui/js/component/fileActions/view.jsx | 152 ++++++++++++--------------- ui/js/component/fileCard/index.js | 9 +- ui/js/component/fileCard/view.jsx | 3 +- ui/js/component/fileTile/index.js | 15 +-- ui/js/component/fileTile/view.jsx | 2 +- ui/js/component/router/index.jsx | 7 +- ui/js/component/router/view.jsx | 33 +++--- ui/js/component/video/index.js | 46 +++++--- ui/js/component/video/view.jsx | 34 +++--- ui/js/lbry.js | 1 - ui/js/main.js | 4 +- ui/js/page/channel/index.js | 24 ++--- ui/js/page/filePage/index.js | 42 +++++--- ui/js/page/filePage/view.jsx | 61 ++++------- ui/js/page/showPage/index.js | 27 ++--- ui/js/page/showPage/view.jsx | 12 +-- ui/js/reducers/app.js | 1 - ui/js/reducers/availability.js | 9 +- ui/js/reducers/claims.js | 9 +- ui/js/reducers/file_info.js | 9 +- ui/js/selectors/app.js | 28 +---- ui/js/selectors/availability.js | 44 +++----- ui/js/selectors/claims.js | 55 ++++------ ui/js/selectors/content.js | 17 +-- ui/js/selectors/cost_info.js | 23 +--- ui/js/selectors/file_info.js | 58 +--------- ui/js/selectors/search.js | 4 +- 35 files changed, 346 insertions(+), 556 deletions(-) diff --git a/ui/js/actions/app.js b/ui/js/actions/app.js index 14bad12cd..64ab286c4 100644 --- a/ui/js/actions/app.js +++ b/ui/js/actions/app.js @@ -6,7 +6,6 @@ import { selectUpgradeDownloadItem, selectUpgradeFilename, selectPageTitle, - selectCurrentPath, } from 'selectors/app' const {remote, ipcRenderer, shell} = require('electron'); diff --git a/ui/js/actions/availability.js b/ui/js/actions/availability.js index 74c85eaa3..501a2eeda 100644 --- a/ui/js/actions/availability.js +++ b/ui/js/actions/availability.js @@ -1,39 +1,29 @@ import * as types from 'constants/action_types' import lbry from 'lbry' import { - selectCurrentUri, -} from 'selectors/app' + selectFetchingAvailability +} from 'selectors/availability' -export function doFetchUriAvailability(uri) { - return function(dispatch, getState) { - dispatch({ - type: types.FETCH_AVAILABILITY_STARTED, - data: { uri } - }) - - const successCallback = (availability) => { - dispatch({ - type: types.FETCH_AVAILABILITY_COMPLETED, - data: { - availability, - uri, - } - }) - } - - const errorCallback = () => { - console.debug('error') - } - - lbry.get_availability({ uri }, successCallback, errorCallback) - } -} - -export function doFetchCurrentUriAvailability() { +export function doFetchAvailability(uri) { return function(dispatch, getState) { const state = getState() - const uri = selectCurrentUri(state) + const alreadyFetching = !!selectFetchingAvailability(state)[uri] - dispatch(doFetchUriAvailability(uri)) + if (!alreadyFetching) { + dispatch({ + type: types.FETCH_AVAILABILITY_STARTED, + data: {uri} + }) + + lbry.get_availability({uri}).then((availability) => { + dispatch({ + type: types.FETCH_AVAILABILITY_COMPLETED, + data: { + availability, + uri, + } + }) + }) + } } -} +} \ No newline at end of file diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 297ae221c..43fbfab9b 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -3,18 +3,15 @@ import lbry from 'lbry' import lbryio from 'lbryio' import lbryuri from 'lbryuri' import rewards from 'rewards' -import { - selectCurrentUri, -} from 'selectors/app' import { selectBalance, } from 'selectors/wallet' import { - selectCurrentUriFileInfo, + selectFileInfoForUri, selectDownloadingByUri, } from 'selectors/file_info' import { - selectCurrentUriCostInfo, + selectCostInfoForUri, } from 'selectors/cost_info' import { selectClaimsByUri, @@ -44,15 +41,6 @@ export function doResolveUri(uri) { certificate, } }) - }).catch(() => { - dispatch({ - type: types.RESOLVE_URI_COMPLETED, - data: { - uri, - claim: null, - certificate: null, - } - }) }) } } @@ -120,8 +108,6 @@ export function doFetchPublishedContent() { export function doFetchFeaturedUris() { return function(dispatch, getState) { - return - const state = getState() dispatch({ @@ -229,10 +215,9 @@ export function doDownloadFile(uri, streamInfo) { } } -export function doLoadVideo() { +export function doLoadVideo(uri) { return function(dispatch, getState) { const state = getState() - const uri = selectCurrentUri(state) dispatch({ type: types.LOADING_VIDEO_STARTED, @@ -259,13 +244,12 @@ export function doLoadVideo() { } } -export function doWatchVideo() { +export function doWatchVideo(uri) { return function(dispatch, getState) { const state = getState() - const uri = selectCurrentUri(state) const balance = selectBalance(state) - const fileInfo = selectCurrentUriFileInfo(state) - const costInfo = selectCurrentUriCostInfo(state) + const fileInfo = selectFileInfoForUri(state, { uri }) + const costInfo = selectCostInfoForUri(state, { uri }) const downloadingByUri = selectDownloadingByUri(state) const alreadyDownloading = !!downloadingByUri[uri] const { cost } = costInfo @@ -287,8 +271,8 @@ export function doWatchVideo() { } // the file is free or we have partially downloaded it - if (cost <= 0.01 || fileInfo.download_directory) { - dispatch(doLoadVideo()) + if (cost <= 0.01 || (fileInfo && fileInfo.download_directory)) { + dispatch(doLoadVideo(uri)) return Promise.resolve() } @@ -302,7 +286,7 @@ export function doWatchVideo() { } } -export function doFetchChannelClaims(uri) { +export function doFetchClaimsByChannel(uri) { return function(dispatch, getState) { dispatch({ type: types.FETCH_CHANNEL_CLAIMS_STARTED, @@ -323,7 +307,7 @@ export function doFetchChannelClaims(uri) { }) }).catch(() => { dispatch({ - type: types.FETCH_CHANNEL_CLAIMS_COMPLETED, + type: types.FETC, data: { uri, claims: [] diff --git a/ui/js/actions/cost_info.js b/ui/js/actions/cost_info.js index 5a6a66604..0e87b9005 100644 --- a/ui/js/actions/cost_info.js +++ b/ui/js/actions/cost_info.js @@ -1,7 +1,4 @@ import * as types from 'constants/action_types' -import { - selectCurrentUri, -} from 'selectors/app' import lbry from 'lbry' export function doFetchCostInfoForUri(uri) { diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index b7611fb3d..87f962471 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -1,11 +1,11 @@ import * as types from 'constants/action_types' import lbry from 'lbry' import { - selectCurrentUri, -} from 'selectors/app' -import { - selectCurrentUriClaimOutpoint, + selectClaimsByUri, } from 'selectors/claims' +import { + selectLoadingByUri, +} from 'selectors/file_info' import { doCloseModal, } from 'actions/app' @@ -14,29 +14,39 @@ const { shell, } = require('electron') -export function doFetchCurrentUriFileInfo() { +export function doFetchFileInfo(uri) { return function(dispatch, getState) { const state = getState() - const uri = selectCurrentUri(state) - const outpoint = selectCurrentUriClaimOutpoint(state) + const claim = selectClaimsByUri(state)[uri] + const outpoint = claim ? `${claim.txid}:${claim.nout}` : null + const alreadyFetching = !!selectLoadingByUri(state)[uri] - dispatch({ - type: types.FETCH_FILE_INFO_STARTED, - data: { - uri, - outpoint, - } - }) + if (!outpoint) { + console.log(claim); + console.log(outpoint); + console.log(selectClaimsByUri(state)) + throw new Error("Unable to get outpoint from claim for URI " + uri); + } - lbry.file_list({ outpoint: outpoint, full_status: true }).then(([fileInfo]) => { + if (!alreadyFetching) { dispatch({ - type: types.FETCH_FILE_INFO_COMPLETED, + type: types.FETCH_FILE_INFO_STARTED, data: { uri, - fileInfo, + outpoint, } }) - }) + + lbry.file_list({outpoint: outpoint, full_status: true}).then(([fileInfo]) => { + dispatch({ + type: types.FETCH_FILE_INFO_COMPLETED, + data: { + uri, + fileInfo, + } + }) + }) + } } } diff --git a/ui/js/component/app/index.js b/ui/js/component/app/index.js index a94c0e6f6..a7ce7ce70 100644 --- a/ui/js/component/app/index.js +++ b/ui/js/component/app/index.js @@ -2,30 +2,19 @@ import React from 'react'; import { connect } from 'react-redux' import { - selectCurrentPage, selectCurrentModal, - selectDrawerOpen, - selectHeaderLinks, - selectSearchTerm, } from 'selectors/app' import { doCheckUpgradeAvailable, - doOpenModal, - doCloseModal, } from 'actions/app' import App from './view' const select = (state) => ({ - currentPage: selectCurrentPage(state), modal: selectCurrentModal(state), - headerLinks: selectHeaderLinks(state), - searchTerm: selectSearchTerm(state) }) const perform = (dispatch) => ({ checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()), - openModal: () => dispatch(doOpenModal()), - closeModal: () => dispatch(doCloseModal()), }) export default connect(select, perform)(App) diff --git a/ui/js/component/app/view.jsx b/ui/js/component/app/view.jsx index e6162c4dd..5e47c81f7 100644 --- a/ui/js/component/app/view.jsx +++ b/ui/js/component/app/view.jsx @@ -20,7 +20,6 @@ class App extends React.Component { render() { const { modal, - headerLinks, } = this.props return
diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index 21a2c05d0..87b4cb330 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -3,8 +3,6 @@ import { connect, } from 'react-redux' import { - selectObscureNsfw, - selectHidePrice, selectHasSignature, selectPlatform, } from 'selectors/app' @@ -14,7 +12,7 @@ import { makeSelectLoadingForUri, } from 'selectors/file_info' import { - makeSelectAvailabilityForUri, + makeSelectIsAvailableForUri, } from 'selectors/availability' import { selectCurrentModal, @@ -23,6 +21,9 @@ import { doCloseModal, doOpenModal, } from 'actions/app' +import { + doFetchAvailability +} from 'actions/availability' import { doOpenFileInShell, doOpenFileInFolder, @@ -36,33 +37,29 @@ import FileActions from './view' const makeSelect = () => { const selectFileInfoForUri = makeSelectFileInfoForUri() - const selectAvailabilityForUri = makeSelectAvailabilityForUri() + const selectIsAvailableForUri = makeSelectIsAvailableForUri() const selectDownloadingForUri = makeSelectDownloadingForUri() - const selectLoadingForUri = makeSelectLoadingForUri() const select = (state, props) => ({ - obscureNsfw: selectObscureNsfw(state), - hidePrice: selectHidePrice(state), - hasSignature: selectHasSignature(state), fileInfo: selectFileInfoForUri(state, props), - availability: selectAvailabilityForUri(state, props), + isAvailable: selectIsAvailableForUri(state, props), platform: selectPlatform(state), modal: selectCurrentModal(state), downloading: selectDownloadingForUri(state, props), - loading: selectLoadingForUri(state, props), }) return select } const perform = (dispatch) => ({ + checkAvailability: (uri) => dispatch(doFetchAvailability(uri)), closeModal: () => dispatch(doCloseModal()), openInFolder: (fileInfo) => dispatch(doOpenFileInFolder(fileInfo)), openInShell: (fileInfo) => dispatch(doOpenFileInShell(fileInfo)), deleteFile: (fileInfo, deleteFromComputer) => dispatch(doDeleteFile(fileInfo, deleteFromComputer)), openModal: (modal) => dispatch(doOpenModal(modal)), - downloadClick: () => dispatch(doWatchVideo()), - loadVideo: () => dispatch(doLoadVideo()) + startDownload: (uri) => dispatch(doWatchVideo(uri)), + loadVideo: (uri) => dispatch(doLoadVideo(uri)) }) -export default connect(makeSelect, perform)(FileActions) +export default connect(makeSelect, perform)(FileActions) \ No newline at end of file diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index 5d74949bc..468e89329 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -1,7 +1,5 @@ import React from 'react'; -import lbry from 'lbry'; -import lbryuri from 'lbryuri'; -import {Icon,} from 'component/common'; +import {Icon,BusyMessage} from 'component/common'; import FilePrice from 'component/filePrice' import {Modal} from 'component/modal'; import {FormField} from 'component/form'; @@ -9,14 +7,36 @@ import Link from 'component/link'; import {ToolTip} from 'component/tooltip'; import {DropDownMenu, DropDownMenuItem} from 'component/menu'; -class FileActionsRow extends React.Component { +class FileActions extends React.Component { constructor(props) { super(props) this.state = { + forceShowActions: false, deleteChecked: false, } } + componentWillMount() { + this.checkAvailability(this.props.uri) + } + + componentWillReceiveProps(nextProps) { + this.checkAvailability(nextProps.uri) + } + + checkAvailability(uri) { + if (!this._uri || uri !== this._uri) { + this._uri = uri; + this.props.checkAvailability(uri) + } + } + + onShowFileActionsRowClicked() { + this.setState({ + forceShowActions: true, + }); + } + handleDeleteCheckboxClicked(event) { this.setState({ deleteChecked: event.target.checked, @@ -25,65 +45,73 @@ class FileActionsRow extends React.Component { onAffirmPurchase() { this.props.closeModal() - this.props.loadVideo() + this.props.loadVideo(this.props.uri) } render() { const { fileInfo, + isAvailable, platform, downloading, - loading, uri, deleteFile, openInFolder, openInShell, modal, openModal, - affirmPurchase, closeModal, - downloadClick, + startDownload, } = this.props - const { - deleteChecked, - } = this.state + const deleteChecked = this.state.deleteChecked, + metadata = fileInfo ? fileInfo.metadata : null, + openInFolderMessage = platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder', + showMenu = fileInfo && Object.keys(fileInfo).length > 0, + title = metadata ? metadata.title : uri; - const metadata = fileInfo ? fileInfo.metadata : null + let content - if (!fileInfo) - { - return null; - } + if (fileInfo === undefined || isAvailable === undefined) { - const openInFolderMessage = platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder', - showMenu = Object.keys(fileInfo).length != 0; + content = + + } else if (!isAvailable && !this.state.forceShowActions) { + + content =
+
Content unavailable.
+ + +
+ + } else if (fileInfo === null && !downloading) { + + content = { startDownload(uri) } } />; + + } else if (downloading) { - let linkBlock; - if (Object.keys(fileInfo).length == 0 && !downloading && !loading) { - linkBlock = ; - } else if (downloading || loading) { const progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0, label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...', labelWithIcon = {label}; - linkBlock = ( -
-
{labelWithIcon}
- {labelWithIcon} -
- ); + content =
+
{labelWithIcon}
+ {labelWithIcon} +
+ + } else if (fileInfo && fileInfo.download_path) { + content = openInShell(fileInfo)} />; } else { - linkBlock = openInShell(fileInfo)} />; + console.log('handle this case of file action props?'); + console.log(this.props) } - const title = metadata ? metadata.title : uri; return ( -
- {fileInfo !== null || fileInfo.isMine - ? linkBlock - : null} +
+ { content } { showMenu ? openInFolder(fileInfo)} label={openInFolderMessage} /> @@ -102,62 +130,18 @@ class FileActionsRow extends React.Component { LBRY was unable to download the stream {uri}. deleteFile(uri, fileInfo, deleteChecked)} - onAborted={closeModal}> + contentLabel="Not enough credits" + type="confirm" + confirmButtonLabel="Remove" + onConfirmed={() => deleteFile(uri, fileInfo, deleteChecked)} + onAborted={closeModal}>

Are you sure you'd like to remove {title} from LBRY?

-
+ ); } } -class FileActions extends React.Component { - constructor(props) { - super(props) - this._isMounted = false - this._fileInfoSubscribeId = null - this.state = { - available: true, - forceShowActions: false, - fileInfo: null, - } - } - - onShowFileActionsRowClicked() { - this.setState({ - forceShowActions: true, - }); - } - - render() { - const { - fileInfo, - availability, - } = this.props - - if (fileInfo === null) { - return null; - } - - return (
- { - fileInfo || this.state.available || this.state.forceShowActions - ? - :
-
Content unavailable.
- - -
- } -
); - } -} - export default FileActions diff --git a/ui/js/component/fileCard/index.js b/ui/js/component/fileCard/index.js index 1fcd3ab9b..643434406 100644 --- a/ui/js/component/fileCard/index.js +++ b/ui/js/component/fileCard/index.js @@ -9,19 +9,17 @@ import { doResolveUri, } from 'actions/content' import { - selectHidePrice, selectObscureNsfw, } from 'selectors/app' import { makeSelectClaimForUri, - makeSelectSourceForUri, makeSelectMetadataForUri, } from 'selectors/claims' import { makeSelectFileInfoForUri, } from 'selectors/file_info' import { - makeSelectResolvingUri, + makeSelectIsResolvingForUri, } from 'selectors/content' import FileCard from './view' @@ -29,17 +27,14 @@ const makeSelect = () => { const selectClaimForUri = makeSelectClaimForUri() const selectFileInfoForUri = makeSelectFileInfoForUri() const selectMetadataForUri = makeSelectMetadataForUri() - const selectSourceForUri = makeSelectSourceForUri() - const selectResolvingUri = makeSelectResolvingUri() + const selectResolvingUri = makeSelectIsResolvingForUri() const select = (state, props) => ({ claim: selectClaimForUri(state, props), fileInfo: selectFileInfoForUri(state, props), - hidePrice: selectHidePrice(state), obscureNsfw: selectObscureNsfw(state), hasSignature: false, metadata: selectMetadataForUri(state, props), - source: selectSourceForUri(state, props), isResolvingUri: selectResolvingUri(state, props), }) diff --git a/ui/js/component/fileCard/view.jsx b/ui/js/component/fileCard/view.jsx index 19e03bc1f..e97f17f92 100644 --- a/ui/js/component/fileCard/view.jsx +++ b/ui/js/component/fileCard/view.jsx @@ -38,7 +38,6 @@ class FileCard extends React.Component { metadata, isResolvingUri, navigate, - hidePrice, } = this.props const uri = lbryuri.normalize(this.props.uri); @@ -59,7 +58,7 @@ class FileCard extends React.Component {
{title}
- { !hidePrice ? : null} +
diff --git a/ui/js/component/fileTile/index.js b/ui/js/component/fileTile/index.js index dd17e8e60..d61e58b64 100644 --- a/ui/js/component/fileTile/index.js +++ b/ui/js/component/fileTile/index.js @@ -10,41 +10,30 @@ import { } from 'actions/content' import { makeSelectClaimForUri, - makeSelectSourceForUri, makeSelectMetadataForUri, } from 'selectors/claims' import { makeSelectFileInfoForUri, } from 'selectors/file_info' -import { - makeSelectFetchingAvailabilityForUri, - makeSelectAvailabilityForUri, -} from 'selectors/availability' import { selectObscureNsfw, } from 'selectors/app' import { - makeSelectResolvingUri, + makeSelectIsResolvingForUri, } from 'selectors/content' import FileTile from './view' const makeSelect = () => { const selectClaimForUri = makeSelectClaimForUri() const selectFileInfoForUri = makeSelectFileInfoForUri() - const selectFetchingAvailabilityForUri = makeSelectFetchingAvailabilityForUri() - const selectAvailabilityForUri = makeSelectAvailabilityForUri() const selectMetadataForUri = makeSelectMetadataForUri() - const selectSourceForUri = makeSelectSourceForUri() - const selectResolvingUri = makeSelectResolvingUri() + const selectResolvingUri = makeSelectIsResolvingForUri() const select = (state, props) => ({ claim: selectClaimForUri(state, props), fileInfo: selectFileInfoForUri(state, props), - fetchingAvailability: selectFetchingAvailabilityForUri(state, props), - selectAvailabilityForUri: selectAvailabilityForUri(state, props), obscureNsfw: selectObscureNsfw(state), metadata: selectMetadataForUri(state, props), - source: selectSourceForUri(state, props), isResolvingUri: selectResolvingUri(state, props), }) diff --git a/ui/js/component/fileTile/view.jsx b/ui/js/component/fileTile/view.jsx index 81fac9fa2..c015c6327 100644 --- a/ui/js/component/fileTile/view.jsx +++ b/ui/js/component/fileTile/view.jsx @@ -97,7 +97,7 @@ class FileTile extends React.Component { } else if (isResolvingUri) { description = "Loading..." } else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) { - onClick = () => navigate('/publish') + onClick = () => navigate('/publish', { }) description = This location is unused. { ' ' } { isClaimable && Put something here! } diff --git a/ui/js/component/router/index.jsx b/ui/js/component/router/index.jsx index c75222949..48bf22ccc 100644 --- a/ui/js/component/router/index.jsx +++ b/ui/js/component/router/index.jsx @@ -2,14 +2,13 @@ import React from 'react'; import { connect } from 'react-redux'; import Router from './view.jsx'; import { - selectCurrentPage + selectCurrentPage, + selectCurrentParams, } from 'selectors/app.js'; const select = (state) => ({ + params: selectCurrentParams(state), currentPage: selectCurrentPage(state) }) -const perform = { -} - export default connect(select, null)(Router); diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx index 8b3d66102..a6d5f988b 100644 --- a/ui/js/component/router/view.jsx +++ b/ui/js/component/router/view.jsx @@ -25,25 +25,26 @@ const route = (page, routesMap) => { const Router = (props) => { const { currentPage, + params, } = props; return route(currentPage, { - 'settings': , - 'help': , - 'report': , - 'downloaded': , - 'published': , - 'start': , - 'wallet': , - 'send': , - 'receive': , - 'show': , - 'channel': , - 'publish': , - 'developer': , - 'discover': , - 'rewards': , - 'search': , + 'settings': , + 'help': , + 'report': , + 'downloaded': , + 'published': , + 'start': , + 'wallet': , + 'send': , + 'receive': , + 'show': , + 'channel': , + 'publish': , + 'developer': , + 'discover': , + 'rewards': , + 'search': , }) } diff --git a/ui/js/component/video/index.js b/ui/js/component/video/index.js index 94978f702..f7f6b9198 100644 --- a/ui/js/component/video/index.js +++ b/ui/js/component/video/index.js @@ -13,30 +13,42 @@ import { doLoadVideo, } from 'actions/content' import { - selectLoadingCurrentUri, - selectCurrentUriFileReadyToPlay, - selectCurrentUriIsPlaying, - selectCurrentUriFileInfo, - selectDownloadingCurrentUri, + makeSelectMetadataForUri +} from 'selectors/claims' +import { + makeSelectFileInfoForUri, + makeSelectLoadingForUri, + makeSelectDownloadingForUri, } from 'selectors/file_info' import { - selectCurrentUriCostInfo, + makeSelectCostInfoForUri, } from 'selectors/cost_info' import Video from './view' -const select = (state) => ({ - costInfo: selectCurrentUriCostInfo(state), - fileInfo: selectCurrentUriFileInfo(state), - modal: selectCurrentModal(state), - isLoading: selectLoadingCurrentUri(state), - readyToPlay: selectCurrentUriFileReadyToPlay(state), - isDownloading: selectDownloadingCurrentUri(state), -}) + +const makeSelect = () => { + const selectCostInfo = makeSelectCostInfoForUri() + const selectFileInfo = makeSelectFileInfoForUri() + const selectIsLoading = makeSelectLoadingForUri() + const selectIsDownloading = makeSelectDownloadingForUri() + const selectMetadata = makeSelectMetadataForUri() + + const select = (state, props) => ({ + costInfo: selectCostInfo(state, props), + fileInfo: selectFileInfo(state, props), + metadata: selectMetadata(state, props), + modal: selectCurrentModal(state), + isLoading: selectIsLoading(state, props), + isDownloading: selectIsDownloading(state, props), + }) + + return select +} const perform = (dispatch) => ({ - loadVideo: () => dispatch(doLoadVideo()), - watchVideo: (elem) => dispatch(doWatchVideo()), + loadVideo: (uri) => dispatch(doLoadVideo(uri)), + watchVideo: (uri) => dispatch(doWatchVideo(uri)), closeModal: () => dispatch(doCloseModal()), }) -export default connect(select, perform)(Video) \ No newline at end of file +export default connect(makeSelect, perform)(Video) \ No newline at end of file diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index 265c31a9f..1dea58524 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -1,17 +1,13 @@ import React from 'react'; -import { - Icon, - Thumbnail, -} from 'component/common'; import FilePrice from 'component/filePrice' import Link from 'component/link'; import Modal from 'component/modal'; -class WatchLink extends React.Component { +class VideoPlayButton extends React.Component { confirmPurchaseClick() { this.props.closeModal() this.props.startPlaying() - this.props.loadVideo() + this.props.loadVideo(this.props.uri) } render() { @@ -32,9 +28,17 @@ class WatchLink extends React.Component { fileInfo, } = this.props + /* + title={ + isLoading ? "Video is Loading" : + !costInfo ? "Waiting on cost info..." : + fileInfo === undefined ? "Waiting on file info..." : "" + } + */ + return (
{ + this.props.watchVideo(this.props.uri).then(() => { if (!this.props.modal) { this.setState({ isPlaying: true @@ -85,8 +89,6 @@ class Video extends React.Component { render() { const { - readyToPlay = false, - thumbnail, metadata, isLoading, isDownloading, @@ -105,14 +107,14 @@ class Video extends React.Component { } return ( -
{ +
{ isPlaying ? - !readyToPlay ? - this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
: - : + (!fileInfo.isReadyToPlay ? + this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
: + ) :
- +
}
); diff --git a/ui/js/lbry.js b/ui/js/lbry.js index d03ceea55..b3772b395 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -642,7 +642,6 @@ lbry.claim_list_mine = function(params={}) { const claimCacheKey = 'resolve_claim_cache'; lbry._claimCache = getSession(claimCacheKey, {}); lbry.resolve = function(params={}) { - console.log('resolve: ' + params.uri); return new Promise((resolve, reject) => { if (!params.uri) { throw "Resolve has hacked cache on top of it that requires a URI" diff --git a/ui/js/main.js b/ui/js/main.js index 6f37050aa..fa4dc5217 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -36,7 +36,9 @@ window.addEventListener('popstate', (event) => { }) ipcRenderer.on('open-uri-requested', (event, uri) => { - console.log('FIX ME do magic dispatch'); + if (uri) { + console.log('FIX ME do magic dispatch: ' + uri); + } }); const initialState = app.store.getState(); diff --git a/ui/js/page/channel/index.js b/ui/js/page/channel/index.js index dbb3fa875..3091761df 100644 --- a/ui/js/page/channel/index.js +++ b/ui/js/page/channel/index.js @@ -3,25 +3,21 @@ import { connect } from 'react-redux' import { - doFetchChannelClaims + doFetchClaimsByChannel } from 'actions/content' import { - selectCurrentUri, -} from 'selectors/app' -import { - selectCurrentUriClaim, - selectCurrentUriClaims, + makeSelectClaimsForChannel } from 'selectors/claims' import ChannelPage from './view' - -const select = (state) => ({ - uri: selectCurrentUri(state), - claim: selectCurrentUriClaim(state), - claims: selectCurrentUriClaims(state) -}) +// +// const select = (state) => ({ +// uri: selectCurrentUri(state), +// claim: selectCurrentUriClaim(state), +// claims: selectCurrentUriClaims(state) +// }) const perform = (dispatch) => ({ - fetchClaims: (uri) => dispatch(doFetchChannelClaims(uri)) + fetchClaims: (uri) => dispatch(doFetchClaimsByChannel(uri)) }) -export default connect(select, perform)(ChannelPage) +export default connect(null, perform)(ChannelPage) diff --git a/ui/js/page/filePage/index.js b/ui/js/page/filePage/index.js index 3d0ba7665..a8fee4d10 100644 --- a/ui/js/page/filePage/index.js +++ b/ui/js/page/filePage/index.js @@ -3,33 +3,41 @@ import { connect } from 'react-redux' import { - doFetchCurrentUriFileInfo + doFetchFileInfo, } from 'actions/file_info' import { - selectCurrentUri, -} from 'selectors/app' -import { - selectCurrentUriFileInfo, - selectCurrentUriIsDownloaded, + makeSelectFileInfoForUri, } from 'selectors/file_info' import { - selectCurrentUriClaim, + makeSelectClaimForUri, + makeSelectContentTypeForUri, + makeSelectMetadataForUri, } from 'selectors/claims' import { - selectCurrentUriCostInfo, + makeSelectCostInfoForUri, } from 'selectors/cost_info' import FilePage from './view' -const select = (state) => ({ - claim: selectCurrentUriClaim(state), - uri: selectCurrentUri(state), - isDownloaded: selectCurrentUriIsDownloaded(state), - fileInfo: selectCurrentUriFileInfo(state), - costInfo: selectCurrentUriCostInfo(state), -}) +const makeSelect = () => { + const selectClaim = makeSelectClaimForUri(), + selectContentType = makeSelectContentTypeForUri(), + selectFileInfo = makeSelectFileInfoForUri(), + selectCostInfo = makeSelectCostInfoForUri(), + selectMetadata = makeSelectMetadataForUri() + + const select = (state, props) => ({ + claim: selectClaim(state, props), + contentType: selectContentType(state, props), + costInfo: selectCostInfo(state, props), + metadata: selectMetadata(state, props), + fileInfo: selectFileInfo(state, props) + }) + + return select +} const perform = (dispatch) => ({ - fetchFileInfo: () => dispatch(doFetchCurrentUriFileInfo()) + fetchFileInfo: (uri) => dispatch(doFetchFileInfo(uri)) }) -export default connect(select, perform)(FilePage) +export default connect(makeSelect, perform)(FilePage) diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index f2b9ab3c8..20b87a83f 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -1,12 +1,9 @@ import React from 'react'; import lbry from 'lbry.js'; -import lighthouse from 'lighthouse.js'; import lbryuri from 'lbryuri.js'; import Video from 'component/video' import { - TruncatedText, Thumbnail, - BusyMessage, } from 'component/common'; import FilePrice from 'component/filePrice' import FileActions from 'component/fileActions'; @@ -57,64 +54,50 @@ class FilePage extends React.Component{ fetchFileInfo(props) { if (props.fileInfo === undefined) { - props.fetchFileInfo() + props.fetchFileInfo(props.uri) } } render() { const { claim, - navigate, - claim: { - txid, - nout, - has_signature: hasSignature, - signature_is_valid: signatureIsValid, - value, - value: { - stream, - stream: { - metadata, - source, - metadata: { - title, - } = {}, - source: { - contentType, - } = {}, - } = {}, - } = {}, - }, + metadata, + contentType, uri, - isDownloaded, fileInfo, - costInfo, - costInfo: { - cost, - includesData: costIncludesData, - } = {}, } = this.props - const outpoint = txid + ':' + nout; - const uriLookupComplete = !!claim && Object.keys(claim).length + if (!claim || !metadata) { + return Empty claim or metadata info. + } + const { + txid, + nout, + has_signature: hasSignature, + signature_is_valid: signatureIsValid, + value + } = claim + + const outpoint = txid + ':' + nout + const title = metadata.title const channelUriObj = lbryuri.parse(uri) delete channelUriObj.path; delete channelUriObj.contentName; - const channelUri = signatureIsValid && hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null; + const channelUri = signatureIsValid && hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null const uriIndicator = return (
{ contentType && contentType.startsWith('video/') ? -
- {isDownloaded === false + {!fileInfo || fileInfo.written_bytes <= 0 ? : null}

{title}

@@ -123,7 +106,8 @@ class FilePage extends React.Component{ uriIndicator}
-
+ +
{metadata && metadata.description} @@ -131,8 +115,7 @@ class FilePage extends React.Component{
{ metadata ?
- +
: '' }
diff --git a/ui/js/page/showPage/index.js b/ui/js/page/showPage/index.js index 1145b03c7..563b9cff3 100644 --- a/ui/js/page/showPage/index.js +++ b/ui/js/page/showPage/index.js @@ -6,26 +6,27 @@ import { doResolveUri, } from 'actions/content' import { - selectCurrentUri, -} from 'selectors/app' -import { - selectCurrentUriClaim, - selectCurrentUriChannelClaim, + makeSelectClaimForUri, } from 'selectors/claims' import { - selectCurrentUriIsResolving, + makeSelectIsResolvingForUri, } from 'selectors/content' import ShowPage from './view' -const select = (state, props) => ({ - channelClaim: selectCurrentUriChannelClaim(state), - claim: selectCurrentUriClaim(state), - uri: selectCurrentUri(state), - isResolvingUri: selectCurrentUriIsResolving(state) -}) +const makeSelect = () => { + const selectClaim = makeSelectClaimForUri(), + selectIsResolving = makeSelectIsResolvingForUri(); + + const select = (state, props) => ({ + claim: selectClaim(state, props), + isResolvingUri: selectIsResolving(state, props) + }) + + return select +} const perform = (dispatch) => ({ resolveUri: (uri) => dispatch(doResolveUri(uri)) }) -export default connect(select, perform)(ShowPage) +export default connect(makeSelect, perform)(ShowPage) diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx index 3d85a10b4..c1358c446 100644 --- a/ui/js/page/showPage/view.jsx +++ b/ui/js/page/showPage/view.jsx @@ -28,7 +28,6 @@ class ShowPage extends React.Component{ render() { const { - channelClaim, claim, uri, isResolvingUri, @@ -36,7 +35,7 @@ class ShowPage extends React.Component{ let innerContent = ""; - if (isResolvingUri || claim === null) { + if (isResolvingUri || !claim) { innerContent =

{uri}

@@ -47,11 +46,12 @@ class ShowPage extends React.Component{
} - else if (channelClaim && claim && channelClaim.txid && channelClaim.txid === claim.txid) { - innerContent = + else if (claim.name.length && claim.name[0] === '@') { + innerContent = "channel" + // innerContent = } else if (claim) { - innerContent = + innerContent = } return ( @@ -60,4 +60,4 @@ class ShowPage extends React.Component{ } } -export default ShowPage +export default ShowPage \ No newline at end of file diff --git a/ui/js/reducers/app.js b/ui/js/reducers/app.js index 883ff068f..e3070ed40 100644 --- a/ui/js/reducers/app.js +++ b/ui/js/reducers/app.js @@ -9,7 +9,6 @@ const defaultState = { upgradeSkipped: sessionStorage.getItem('upgradeSkipped'), daemonReady: false, obscureNsfw: !lbry.getClientSetting('showNsfw'), - hidePrice: false, hasSignature: false, } diff --git a/ui/js/reducers/availability.js b/ui/js/reducers/availability.js index 6c0e28a8b..6fe6e4ddf 100644 --- a/ui/js/reducers/availability.js +++ b/ui/js/reducers/availability.js @@ -9,10 +9,8 @@ reducers[types.FETCH_AVAILABILITY_STARTED] = function(state, action) { uri, } = action.data const newFetching = Object.assign({}, state.fetching) - const newByUri = Object.assign({}, newFetching.byUri) - newByUri[uri] = true - newFetching.byUri = newByUri + newFetching[uri] = true return Object.assign({}, state, { fetching: newFetching, @@ -24,12 +22,11 @@ reducers[types.FETCH_AVAILABILITY_COMPLETED] = function(state, action) { uri, availability, } = action.data + const newFetching = Object.assign({}, state.fetching) - const newFetchingByUri = Object.assign({}, newFetching.byUri) const newAvailabilityByUri = Object.assign({}, state.byUri) - delete newFetchingByUri[uri] - newFetching.byUri = newFetchingByUri + delete newFetching[uri] newAvailabilityByUri[uri] = availability return Object.assign({}, state, { diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index 73b1c34a0..683f52ef1 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -13,23 +13,22 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { } = action.data const newClaims = Object.assign({}, state.claimsByUri) - const newChannelClaims = Object.assign({}, state.channelClaimsByUri) if (claim !== undefined) { newClaims[uri] = claim } //This needs a sanity boost... - if (certificate !== undefined) { - newChannelClaims[uri] = certificate + if (certificate !== undefined && claim === undefined) { + const uriParts = lbryuri.parse(uri); + // newChannelClaims[uri] = certificate if (claim === undefined) { newClaims[uri] = certificate } } return Object.assign({}, state, { - claimsByUri: newClaims, - channelClaimsByUri: newChannelClaims + claimsByUri: newClaims }) } diff --git a/ui/js/reducers/file_info.js b/ui/js/reducers/file_info.js index 292508a2b..d0e69e148 100644 --- a/ui/js/reducers/file_info.js +++ b/ui/js/reducers/file_info.js @@ -23,10 +23,17 @@ reducers[types.FETCH_FILE_INFO_COMPLETED] = function(state, action) { uri, fileInfo, } = action.data + const newByUri = Object.assign({}, state.byUri) const newFetching = Object.assign({}, state.fetching) - newByUri[uri] = fileInfo || {} + if (fileInfo) { + fileInfo.isReadyToPlay = fileInfo.written_bytes > 0 + fileInfo.isDownloaded = fileInfo.completed && fileInfo.written_bytes > 0; + } + + newByUri[uri] = fileInfo || null + delete newFetching[uri] return Object.assign({}, state, { diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js index a1d9ce400..94a595357 100644 --- a/ui/js/selectors/app.js +++ b/ui/js/selectors/app.js @@ -31,22 +31,10 @@ export const selectCurrentParams = createSelector( } ) -export const selectCurrentUri = createSelector( - selectCurrentPath, - (path) => { - if (path.match(/=/)) { - return path.split('=')[1] - } - else { - return undefined - } - } -) - export const selectPageTitle = createSelector( selectCurrentPage, - selectCurrentUri, - (page, uri) => { + selectCurrentParams, + (page, params) => { switch (page) { case 'search': return 'Search' @@ -62,7 +50,7 @@ export const selectPageTitle = createSelector( case 'rewards': return page.charAt(0).toUpperCase() + page.slice(1) case 'show': - return lbryuri.normalize(uri) + return lbryuri.normalize(params.uri) case 'downloaded': return 'Downloads & Purchases' case 'published': @@ -190,11 +178,6 @@ export const selectUpgradeDownloadItem = createSelector( (state) => state.downloadItem ) -export const selectSearchTerm = createSelector( - _selectState, - (state) => state.searchTerm -) - export const selectError = createSelector( _selectState, (state) => state.error @@ -210,11 +193,6 @@ export const selectObscureNsfw = createSelector( (state) => !!state.obscureNsfw ) -export const selectHidePrice = createSelector( - _selectState, - (state) => !!state.hidePrice -) - export const selectHasSignature = createSelector( _selectState, (state) => !!state.hasSignature diff --git a/ui/js/selectors/availability.js b/ui/js/selectors/availability.js index 0eaebc318..8b65c5ec6 100644 --- a/ui/js/selectors/availability.js +++ b/ui/js/selectors/availability.js @@ -4,7 +4,6 @@ import { import { selectDaemonReady, selectCurrentPage, - selectCurrentUri, } from 'selectors/app' const _selectState = state => state.availability @@ -14,29 +13,24 @@ export const selectAvailabilityByUri = createSelector( (state) => state.byUri || {} ) +const selectAvailabilityForUri = (state, props) => { + return selectAvailabilityByUri(state)[props.uri] +} + +export const makeSelectIsAvailableForUri = () => { + return createSelector( + selectAvailabilityForUri, + (availability) => availability === undefined ? undefined : availability > 0 + ) +} + export const selectFetchingAvailability = createSelector( _selectState, (state) => state.fetching || {} ) -export const selectFetchingAvailabilityByUri = createSelector( - selectFetchingAvailability, - (fetching) => fetching.byUri || {} -) - -const selectAvailabilityForUri = (state, props) => { - return selectAvailabilityByUri(state)[props.uri] -} - -export const makeSelectAvailabilityForUri = () => { - return createSelector( - selectAvailabilityForUri, - (availability) => availability - ) -} - const selectFetchingAvailabilityForUri = (state, props) => { - return selectFetchingAvailabilityByUri(state)[props.uri] + return selectFetchingAvailability(state)[props.uri] } export const makeSelectFetchingAvailabilityForUri = () => { @@ -44,16 +38,4 @@ export const makeSelectFetchingAvailabilityForUri = () => { selectFetchingAvailabilityForUri, (fetching) => fetching ) -} - -export const selectFetchingAvailabilityForCurrentUri = createSelector( - selectCurrentUri, - selectFetchingAvailabilityByUri, - (uri, byUri) => byUri[uri] -) - -export const selectAvailabilityForCurrentUri = createSelector( - selectCurrentUri, - selectAvailabilityByUri, - (uri, byUri) => byUri[uri] -) \ No newline at end of file +} \ No newline at end of file diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index fc6593606..9b7612859 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -2,9 +2,6 @@ import { createSelector, } from 'reselect' import lbryuri from 'lbryuri' -import { - selectCurrentUri, -} from 'selectors/app' export const _selectState = state => state.claims || {} @@ -13,40 +10,21 @@ export const selectClaimsByUri = createSelector( (state) => state.claimsByUri || {} ) -export const selectCurrentUriClaim = createSelector( - selectCurrentUri, - selectClaimsByUri, - (uri, byUri) => byUri[uri] -) - -export const selectChannelClaimsByUri = createSelector( - _selectState, - (state) => state.channelClaimsByUri || {} -) - -export const selectCurrentUriChannelClaim = createSelector( - selectCurrentUri, - selectChannelClaimsByUri, - (uri, byUri) => byUri[uri] -) - -export const selectCurrentUriClaimOutpoint = createSelector( - selectCurrentUriClaim, - (claim) => { - return claim ? `${claim.txid}:${claim.nout}` : null - } -) - -export const selectClaimsByChannel = createSelector( +export const selectAllClaimsByChannel = createSelector( _selectState, (state) => state.claimsByChannel || {} ) -export const selectCurrentUriClaims = createSelector( - selectCurrentUri, - selectClaimsByChannel, - (uri, byChannel) => byChannel[uri] -) +export const selectClaimsForChannel = (state, props) => { + return selectAllClaimsByChannel(state)[props.uri] +} + +export const makeSelectClaimsForChannel = () => { + return createSelector( + selectClaimsForChannel, + (claim) => claim + ) +} const selectClaimForUri = (state, props) => { const uri = lbryuri.normalize(props.uri) @@ -64,7 +42,7 @@ const selectMetadataForUri = (state, props) => { const claim = selectClaimForUri(state, props) const metadata = claim && claim.value && claim.value.stream && claim.value.stream.metadata - return metadata ? metadata : undefined + return metadata ? metadata : (claim === undefined ? undefined : null) } export const makeSelectMetadataForUri = () => { @@ -78,7 +56,7 @@ const selectSourceForUri = (state, props) => { const claim = selectClaimForUri(state, props) const source = claim && claim.value && claim.value.stream && claim.value.stream.source - return source ? source : undefined + return source ? source : (claim === undefined ? undefined : null) } export const makeSelectSourceForUri = () => { @@ -88,6 +66,13 @@ export const makeSelectSourceForUri = () => { ) } +export const makeSelectContentTypeForUri = () => { + return createSelector( + selectSourceForUri, + (source) => source ? source.contentType : source + ) +} + export const selectMyClaims = createSelector( _selectState, (state) => state.mine || {} diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js index 6ee54bf94..03fda8112 100644 --- a/ui/js/selectors/content.js +++ b/ui/js/selectors/content.js @@ -2,7 +2,6 @@ import { createSelector } from 'reselect' import { selectDaemonReady, selectCurrentPage, - selectCurrentUri, } from 'selectors/app' export const _selectState = state => state.content || {} @@ -17,10 +16,6 @@ export const selectFetchingFeaturedUris = createSelector( (state) => !!state.fetchingFeaturedContent ) -export const selectFetchingFileInfos = createSelector( - _selectState, - (state) => state.fetchingFileInfos || {} -) export const selectFetchingDownloadedContent = createSelector( _selectState, @@ -47,24 +42,16 @@ export const selectPublishedContent = createSelector( (state) => state.publishedContent || {} ) - -export const selectResolvingUris = createSelector( +const selectResolvingUris = createSelector( _selectState, (state) => state.resolvingUris || [] ) - -export const selectCurrentUriIsResolving = createSelector( - selectCurrentUri, - selectResolvingUris, - (uri, resolvingUris) => resolvingUris.indexOf(uri) != -1 -) - const selectResolvingUri = (state, props) => { return selectResolvingUris(state).indexOf(props.uri) != -1 } -export const makeSelectResolvingUri = () => { +export const makeSelectIsResolvingForUri = () => { return createSelector( selectResolvingUri, (resolving) => resolving diff --git a/ui/js/selectors/cost_info.js b/ui/js/selectors/cost_info.js index da55c89af..242ec6b0d 100644 --- a/ui/js/selectors/cost_info.js +++ b/ui/js/selectors/cost_info.js @@ -1,8 +1,4 @@ import { createSelector } from 'reselect' -import { - selectCurrentUri, - selectCurrentPage, -} from 'selectors/app' export const _selectState = state => state.costInfo || {} @@ -11,24 +7,7 @@ export const selectAllCostInfoByUri = createSelector( (state) => state.byUri || {} ) -export const selectCurrentUriCostInfo = createSelector( - selectCurrentUri, - selectAllCostInfoByUri, - (uri, byUri) => byUri[uri] -) - -export const selectFetchingCostInfo = createSelector( - _selectState, - (state) => state.fetching || {} -) - -export const selectFetchingCurrentUriCostInfo = createSelector( - selectCurrentUri, - selectFetchingCostInfo, - (uri, byUri) => !!byUri[uri] -) - -const selectCostInfoForUri = (state, props) => { +export const selectCostInfoForUri = (state, props) => { return selectAllCostInfoByUri(state)[props.uri] } diff --git a/ui/js/selectors/file_info.js b/ui/js/selectors/file_info.js index b41d5ae49..76fb0031d 100644 --- a/ui/js/selectors/file_info.js +++ b/ui/js/selectors/file_info.js @@ -1,10 +1,6 @@ import { createSelector, } from 'reselect' -import { - selectCurrentUri, - selectCurrentPage, -} from 'selectors/app' import { selectMyClaimsOutpoints, } from 'selectors/claims' @@ -16,28 +12,6 @@ export const selectAllFileInfoByUri = createSelector( (state) => state.byUri || {} ) -export const selectCurrentUriRawFileInfo = createSelector( - selectCurrentUri, - selectAllFileInfoByUri, - (uri, byUri) => byUri[uri] -) - -export const selectCurrentUriFileInfo = createSelector( - selectCurrentUriRawFileInfo, - (fileInfo) => fileInfo -) - -export const selectFetchingFileInfo = createSelector( - _selectState, - (state) => state.fetching || {} -) - -export const selectFetchingCurrentUriFileInfo = createSelector( - selectCurrentUri, - selectFetchingFileInfo, - (uri, byUri) => !!byUri[uri] -) - export const selectDownloading = createSelector( _selectState, (state) => state.downloading || {} @@ -48,24 +22,7 @@ export const selectDownloadingByUri = createSelector( (downloading) => downloading.byUri || {} ) -export const selectDownloadingCurrentUri = createSelector( - selectCurrentUri, - selectDownloadingByUri, - (uri, byUri) => !!byUri[uri] -) - -export const selectCurrentUriIsDownloaded = createSelector( - selectCurrentUriFileInfo, - (fileInfo) => { - if (!fileInfo) return false - if (!fileInfo.completed) return false - if (!fileInfo.written_bytes > 0) return false - - return true - } -) - -const selectFileInfoForUri = (state, props) => { +export const selectFileInfoForUri = (state, props) => { return selectAllFileInfoByUri(state)[props.uri] } @@ -98,19 +55,6 @@ export const selectLoadingByUri = createSelector( (loading) => loading.byUri || {} ) -export const selectLoadingCurrentUri = createSelector( - selectLoadingByUri, - selectCurrentUri, - (byUri, uri) => !!byUri[uri] -) - -// TODO make this smarter so it doesn't start playing and immediately freeze -// while downloading more. -export const selectCurrentUriFileReadyToPlay = createSelector( - selectCurrentUriFileInfo, - (fileInfo) => (fileInfo || {}).written_bytes > 0 -) - const selectLoadingForUri = (state, props) => { const byUri = selectLoadingByUri(state) return byUri[props.uri] diff --git a/ui/js/selectors/search.js b/ui/js/selectors/search.js index 12dec7658..6bfa70b7d 100644 --- a/ui/js/selectors/search.js +++ b/ui/js/selectors/search.js @@ -2,7 +2,6 @@ import { createSelector } from 'reselect' import { selectPageTitle, selectCurrentPage, - selectCurrentUri } from 'selectors/app' export const _selectState = state => state.search || {} @@ -43,8 +42,7 @@ export const selectWunderBarAddress = createSelector( export const selectWunderBarIcon = createSelector( selectCurrentPage, - selectCurrentUri, - (page, uri) => { + (page) => { switch (page) { case 'search': return 'icon-search' From aa935c1c07a0e02cb4c994c2f20bd278b34f2bda Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Mon, 15 May 2017 12:34:33 -0400 Subject: [PATCH 14/18] more refactors, fixes --- ui/js/actions/content.js | 43 +++++++++++++++++--------- ui/js/actions/file_info.js | 7 ----- ui/js/component/app/index.js | 4 +++ ui/js/component/app/view.jsx | 7 ++++- ui/js/component/fileActions/index.js | 1 - ui/js/component/fileActions/view.jsx | 9 ++++-- ui/js/component/fileCard/index.js | 2 ++ ui/js/component/fileCard/view.jsx | 16 ++++++++-- ui/js/component/fileList/view.jsx | 4 ++- ui/js/component/filePrice/index.js | 3 +- ui/js/component/video/view.jsx | 13 +++++--- ui/js/jsonrpc.js | 2 ++ ui/js/lbry.js | 17 +++++----- ui/js/page/fileListDownloaded/view.jsx | 12 ++++--- ui/js/page/fileListPublished/view.jsx | 13 +++++--- ui/js/reducers/file_info.js | 5 --- ui/js/selectors/app.js | 7 +---- ui/js/selectors/content.js | 4 +-- ui/scss/_gui.scss | 8 +++++ 19 files changed, 113 insertions(+), 64 deletions(-) diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 43fbfab9b..74f0f3f74 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -10,6 +10,9 @@ import { selectFileInfoForUri, selectDownloadingByUri, } from 'selectors/file_info' +import { + selectResolvingUris +} from 'selectors/content' import { selectCostInfoForUri, } from 'selectors/cost_info' @@ -22,26 +25,38 @@ import { export function doResolveUri(uri) { return function(dispatch, getState) { - dispatch({ - type: types.RESOLVE_URI_STARTED, - data: { uri } - }) - lbry.resolve({ uri }).then((resolutionInfo) => { - const { - claim, - certificate, - } = resolutionInfo ? resolutionInfo : { claim : null, certificate: null } + const state = getState() + const alreadyResolving = selectResolvingUris(state).indexOf(uri) !== -1 + if (!alreadyResolving) { dispatch({ - type: types.RESOLVE_URI_COMPLETED, - data: { - uri, + type: types.RESOLVE_URI_STARTED, + data: { uri } + }) + + lbry.resolve({ uri }).then((resolutionInfo) => { + const { claim, certificate, - } + } = resolutionInfo ? resolutionInfo : { claim : null, certificate: null } + + dispatch({ + type: types.RESOLVE_URI_COMPLETED, + data: { + uri, + claim, + certificate, + } + }) }) - }) + } + } +} + +export function doCancelResolveUri(uri) { + return function(dispatch, getState) { + lbry.cancelResolve({ uri }) } } diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index 87f962471..f7d2b08f3 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -21,13 +21,6 @@ export function doFetchFileInfo(uri) { const outpoint = claim ? `${claim.txid}:${claim.nout}` : null const alreadyFetching = !!selectLoadingByUri(state)[uri] - if (!outpoint) { - console.log(claim); - console.log(outpoint); - console.log(selectClaimsByUri(state)) - throw new Error("Unable to get outpoint from claim for URI " + uri); - } - if (!alreadyFetching) { dispatch({ type: types.FETCH_FILE_INFO_STARTED, diff --git a/ui/js/component/app/index.js b/ui/js/component/app/index.js index a7ce7ce70..dcb94bd0f 100644 --- a/ui/js/component/app/index.js +++ b/ui/js/component/app/index.js @@ -7,6 +7,9 @@ import { import { doCheckUpgradeAvailable, } from 'actions/app' +import { + doUpdateBalance, +} from 'actions/wallet' import App from './view' const select = (state) => ({ @@ -15,6 +18,7 @@ const select = (state) => ({ const perform = (dispatch) => ({ checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()), + updateBalance: (balance) => dispatch(doUpdateBalance(balance)) }) export default connect(select, perform)(App) diff --git a/ui/js/component/app/view.jsx b/ui/js/component/app/view.jsx index 5e47c81f7..1c7ff4eb4 100644 --- a/ui/js/component/app/view.jsx +++ b/ui/js/component/app/view.jsx @@ -4,7 +4,8 @@ import Header from 'component/header'; import ErrorModal from 'component/errorModal' import DownloadingModal from 'component/downloadingModal' import UpgradeModal from 'component/upgradeModal' -import {Line} from 'rc-progress'; +import lbry from 'lbry' +import {Line} from 'rc-progress' class App extends React.Component { componentWillMount() { @@ -15,6 +16,10 @@ class App extends React.Component { if (!this.props.upgradeSkipped) { this.props.checkUpgradeAvailable() } + + lbry.balanceSubscribe((balance) => { + this.props.updateBalance(balance) + }) } render() { diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index 87b4cb330..c238f36b8 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -3,7 +3,6 @@ import { connect, } from 'react-redux' import { - selectHasSignature, selectPlatform, } from 'selectors/app' import { diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index 468e89329..ec2b93587 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -72,11 +72,14 @@ class FileActions extends React.Component { let content - if (fileInfo === undefined || isAvailable === undefined) { + console.log('file actions render') + console.log(this.props) + + if (!fileInfo && isAvailable === undefined) { content = - } else if (!isAvailable && !this.state.forceShowActions) { + } else if (!fileInfo && !isAvailable && !this.state.forceShowActions) { content =
Content unavailable.
@@ -119,7 +122,7 @@ class FileActions extends React.Component { : '' } - Are you sure you'd like to buy {title} for credits? + This will purchase {title} for credits. diff --git a/ui/js/component/fileCard/index.js b/ui/js/component/fileCard/index.js index 643434406..e3e11057e 100644 --- a/ui/js/component/fileCard/index.js +++ b/ui/js/component/fileCard/index.js @@ -7,6 +7,7 @@ import { } from 'actions/app' import { doResolveUri, + doCancelResolveUri, } from 'actions/content' import { selectObscureNsfw, @@ -44,6 +45,7 @@ const makeSelect = () => { const perform = (dispatch) => ({ navigate: (path, params) => dispatch(doNavigate(path, params)), resolveUri: (uri) => dispatch(doResolveUri(uri)), + cancelResolveUri: (uri) => dispatch(doCancelResolveUri(uri)) }) export default connect(makeSelect, perform)(FileCard) diff --git a/ui/js/component/fileCard/view.jsx b/ui/js/component/fileCard/view.jsx index e97f17f92..371a955e6 100644 --- a/ui/js/component/fileCard/view.jsx +++ b/ui/js/component/fileCard/view.jsx @@ -8,18 +8,30 @@ import UriIndicator from 'component/uriIndicator'; class FileCard extends React.Component { componentDidMount() { + this.resolve(this.props) + } + + componentWillReceiveProps(nextProps) { + this.resolve(nextProps) + } + + resolve(props) { const { isResolvingUri, resolveUri, claim, uri, - } = this.props + } = props - if(!isResolvingUri && !claim && uri) { + if(!isResolvingUri && claim === undefined && uri) { resolveUri(uri) } } + componentWillUnmount() { + this.props.cancelResolveUri(this.props.uri) + } + handleMouseOver() { this.setState({ hovered: true, diff --git a/ui/js/component/fileList/view.jsx b/ui/js/component/fileList/view.jsx index ebd94c0ee..6130a5ffb 100644 --- a/ui/js/component/fileList/view.jsx +++ b/ui/js/component/fileList/view.jsx @@ -58,6 +58,7 @@ class FileList extends React.Component { render() { const { handleSortChanged, + fetching, fileInfos, hidePrices, } = this.props @@ -74,7 +75,8 @@ class FileList extends React.Component { content.push() }) return ( -
+
+ { fetching && } Sort by { ' ' } diff --git a/ui/js/component/filePrice/index.js b/ui/js/component/filePrice/index.js index b2271e493..62b917b76 100644 --- a/ui/js/component/filePrice/index.js +++ b/ui/js/component/filePrice/index.js @@ -20,7 +20,8 @@ const makeSelect = () => { } const perform = (dispatch) => ({ - fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)) + fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)), + cancelFetchCostInfo: (uri) => dispatch(doCancelFetchCostInfoForUri(uri)) }) export default connect(makeSelect, perform)(FilePrice) diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index 1dea58524..447d87d15 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -38,7 +38,7 @@ class VideoPlayButton extends React.Component { return (
- Are you sure you'd like to buy {this.props.metadata.title} for credits? + This will purchase {title} for credits. @@ -98,6 +98,11 @@ class Video extends React.Component { isPlaying = false, } = this.state + const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0 + + console.log('video render') + console.log(this.props) + let loadStatusMessage = '' if (isLoading) { @@ -107,9 +112,9 @@ class Video extends React.Component { } return ( -
{ +
{ isPlaying ? - (!fileInfo.isReadyToPlay ? + (!isReadyToPlay ? this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
: ) :
diff --git a/ui/js/jsonrpc.js b/ui/js/jsonrpc.js index 654931bb5..378e850a2 100644 --- a/ui/js/jsonrpc.js +++ b/ui/js/jsonrpc.js @@ -68,6 +68,8 @@ jsonrpc.call = function (connectionString, method, params, callback, errorCallba })); sessionStorage.setItem('JSONRPCCounter', counter + 1); + + return xhr }; export default jsonrpc; diff --git a/ui/js/lbry.js b/ui/js/lbry.js index b3772b395..8a8a16bf7 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -95,7 +95,7 @@ let lbry = { }; lbry.call = function (method, params, callback, errorCallback, connectFailedCallback) { - jsonrpc.call(lbry.daemonConnectionString, method, params, callback, errorCallback, connectFailedCallback); + return jsonrpc.call(lbry.daemonConnectionString, method, params, callback, errorCallback, connectFailedCallback); } //core @@ -177,11 +177,6 @@ lbry.setDaemonSetting = function(setting, value, callback) { lbry.call('set_settings', setSettingsArgs, callback) } - -lbry.getBalance = function(callback) { - lbry.call("wallet_balance", {}, callback); -} - lbry.sendToAddress = function(amount, address, callback, errorCallback) { lbry.call("send_amount_to_address", { "amount" : amount, "address": address }, callback, errorCallback); } @@ -641,6 +636,7 @@ lbry.claim_list_mine = function(params={}) { const claimCacheKey = 'resolve_claim_cache'; lbry._claimCache = getSession(claimCacheKey, {}); +lbry._resolveXhrs = {} lbry.resolve = function(params={}) { return new Promise((resolve, reject) => { if (!params.uri) { @@ -649,7 +645,7 @@ lbry.resolve = function(params={}) { if (params.uri && lbry._claimCache[params.uri] !== undefined) { resolve(lbry._claimCache[params.uri]); } else { - lbry.call('resolve', params, function(data) { + lbry._resolveXhrs[params.uri] = lbry.call('resolve', params, function(data) { if (data !== undefined) { lbry._claimCache[params.uri] = data; } @@ -660,6 +656,13 @@ lbry.resolve = function(params={}) { }); } +lbry.cancelResolve = function(params={}) { + const xhr = lbry._resolveXhrs[params.uri] + if (xhr && xhr.readyState > 0 && xhr.readyState < 4) { + xhr.abort() + } +} + // Adds caching. lbry._settingsPromise = null; lbry.settings_get = function(params={}) { diff --git a/ui/js/page/fileListDownloaded/view.jsx b/ui/js/page/fileListDownloaded/view.jsx index 8006828dd..2c041a267 100644 --- a/ui/js/page/fileListDownloaded/view.jsx +++ b/ui/js/page/fileListDownloaded/view.jsx @@ -23,12 +23,14 @@ class FileListDownloaded extends React.Component { } = this.props let content - if (fetching) { - content = - } else if (!downloadedContent.length) { - content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! + if (downloadedContent && downloadedContent.length > 0) { + content = } else { - content = + if (fetching) { + content = + } else { + content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! + } } return ( diff --git a/ui/js/page/fileListPublished/view.jsx b/ui/js/page/fileListPublished/view.jsx index 704a76cff..365aa061c 100644 --- a/ui/js/page/fileListPublished/view.jsx +++ b/ui/js/page/fileListPublished/view.jsx @@ -44,12 +44,15 @@ class FileListPublished extends React.Component { } = this.props let content - if (fetching) { - content = - } else if (!publishedContent.length) { - content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! + + if (publishedContent && publishedContent.length > 0) { + content = } else { - content = + if (fetching) { + content = + } else { + content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! + } } return ( diff --git a/ui/js/reducers/file_info.js b/ui/js/reducers/file_info.js index d0e69e148..951b0f213 100644 --- a/ui/js/reducers/file_info.js +++ b/ui/js/reducers/file_info.js @@ -27,11 +27,6 @@ reducers[types.FETCH_FILE_INFO_COMPLETED] = function(state, action) { const newByUri = Object.assign({}, state.byUri) const newFetching = Object.assign({}, state.fetching) - if (fileInfo) { - fileInfo.isReadyToPlay = fileInfo.written_bytes > 0 - fileInfo.isDownloaded = fileInfo.completed && fileInfo.written_bytes > 0; - } - newByUri[uri] = fileInfo || null delete newFetching[uri] diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js index 94a595357..f0af3b5a1 100644 --- a/ui/js/selectors/app.js +++ b/ui/js/selectors/app.js @@ -191,9 +191,4 @@ export const selectDaemonReady = createSelector( export const selectObscureNsfw = createSelector( _selectState, (state) => !!state.obscureNsfw -) - -export const selectHasSignature = createSelector( - _selectState, - (state) => !!state.hasSignature -) +) \ No newline at end of file diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js index 03fda8112..22476b229 100644 --- a/ui/js/selectors/content.js +++ b/ui/js/selectors/content.js @@ -42,7 +42,7 @@ export const selectPublishedContent = createSelector( (state) => state.publishedContent || {} ) -const selectResolvingUris = createSelector( +export const selectResolvingUris = createSelector( _selectState, (state) => state.resolvingUris || [] ) @@ -56,4 +56,4 @@ export const makeSelectIsResolvingForUri = () => { selectResolvingUri, (resolving) => resolving ) -} +} \ No newline at end of file diff --git a/ui/scss/_gui.scss b/ui/scss/_gui.scss index 3d85f4b22..f4ededba0 100644 --- a/ui/scss/_gui.scss +++ b/ui/scss/_gui.scss @@ -143,6 +143,14 @@ p font-style: italic; } +/*should be redone/moved*/ +.file-list__header { + .busy-indicator { + float: left; + margin-top: 12px; + } +} + .sort-section { display: block; margin-bottom: $spacing-vertical * 2/3; From 3fa4d0dfe7126714fa6117dda8e8c5e8074a95a1 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Wed, 17 May 2017 17:52:45 -0400 Subject: [PATCH 15/18] progress towards fixing settings and costs --- ui/js/actions/app.js | 12 +- ui/js/actions/content.js | 2 +- ui/js/actions/cost_info.js | 69 +++++++-- ui/js/actions/search.js | 3 + ui/js/actions/settings.js | 31 ++++ ui/js/component/fileActions/index.js | 4 +- ui/js/component/fileCard/view.jsx | 2 +- ui/js/component/filePrice/index.js | 2 +- ui/js/component/router/view.jsx | 2 +- ui/js/component/video/index.js | 4 +- ui/js/component/video/view.jsx | 47 +++--- ui/js/constants/action_types.js | 3 + ui/js/lbry.js | 146 ++++++++++-------- ui/js/main.js | 17 +- ui/js/page/help/{index.jsx => index.js} | 0 ui/js/page/search/view.jsx | 2 + ui/js/page/settings/index.js | 21 +++ ui/js/page/{settings.js => settings/view.jsx} | 46 +++--- ui/js/reducers/settings.js | 16 ++ ui/js/selectors/settings.js | 20 +++ ui/js/store.js | 2 + ui/scss/component/_video.scss | 8 + 22 files changed, 313 insertions(+), 146 deletions(-) create mode 100644 ui/js/actions/settings.js rename ui/js/page/help/{index.jsx => index.js} (100%) create mode 100644 ui/js/page/settings/index.js rename ui/js/page/{settings.js => settings/view.jsx} (85%) create mode 100644 ui/js/reducers/settings.js create mode 100644 ui/js/selectors/settings.js diff --git a/ui/js/actions/app.js b/ui/js/actions/app.js index 64ab286c4..c35042a90 100644 --- a/ui/js/actions/app.js +++ b/ui/js/actions/app.js @@ -31,8 +31,7 @@ export function doNavigate(path, params = {}) { const state = getState() const pageTitle = selectPageTitle(state) - history.pushState(params, pageTitle, url) - window.document.title = pageTitle + dispatch(doHistoryPush(params, pageTitle, url)) } } @@ -54,7 +53,14 @@ export function doHistoryBack() { } } -export function doLogoClick() { +export function doHistoryPush(params, title, relativeUrl) { + return function(dispatch, getState) { + let pathParts = window.location.pathname.split('/') + pathParts[pathParts.length - 1] = relativeUrl.replace(/^\//, '') + const url = pathParts.join('/') + history.pushState(params, title, url) + window.document.title = title + } } export function doOpenModal(modal) { diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 74f0f3f74..a565b6e22 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -259,7 +259,7 @@ export function doLoadVideo(uri) { } } -export function doWatchVideo(uri) { +export function doPurchaseUri(uri) { return function(dispatch, getState) { const state = getState() const balance = selectBalance(state) diff --git a/ui/js/actions/cost_info.js b/ui/js/actions/cost_info.js index 0e87b9005..b0f6af6d7 100644 --- a/ui/js/actions/cost_info.js +++ b/ui/js/actions/cost_info.js @@ -1,16 +1,43 @@ import * as types from 'constants/action_types' import lbry from 'lbry' +import lbryio from 'lbryio' +import { + selectClaimsByUri +} from 'selectors/claims' +import { + selectSettingsIsGenerous +} from 'selectors/settings' export function doFetchCostInfoForUri(uri) { return function(dispatch, getState) { - dispatch({ - type: types.FETCH_COST_INFO_STARTED, - data: { - uri, - } - }) + const state = getState(), + claim = selectClaimsByUri(state)[uri], + isGenerous = selectSettingsIsGenerous(state) - lbry.getCostInfo(uri).then(costInfo => { + // + // function getCostGenerous(uri) { + // console.log('get cost generous: ' + uri) + // // If generous is on, the calculation is simple enough that we might as well do it here in the front end + // lbry.resolve({uri: uri}).then((resolutionInfo) => { + // console.log('resolve inside getCostGenerous ' + uri) + // console.log(resolutionInfo) + // if (!resolutionInfo) { + // return reject(new Error("Unused URI")); + // } + + // }); + // } + + function begin() { + dispatch({ + type: types.FETCH_COST_INFO_STARTED, + data: { + uri, + } + }) + } + + function resolve(costInfo) { dispatch({ type: types.FETCH_COST_INFO_COMPLETED, data: { @@ -18,15 +45,25 @@ export function doFetchCostInfoForUri(uri) { costInfo, } }) - }).catch(() => { - dispatch({ - type: types.FETCH_COST_INFO_COMPLETED, - data: { - uri, - costInfo: null - } - }) - }) + } + + if (isGenerous && claim) { + let cost + const fee = claim.value.stream.metadata.fee; + if (fee === undefined ) { + resolve({ cost: 0, includesData: true }) + } else if (fee.currency == 'LBC') { + resolve({ cost: fee.amount, includesData: true }) + } else { + begin() + lbryio.getExchangeRates().then(({lbc_usd}) => { + resolve({ cost: fee.amount / lbc_usd, includesData: true }) + }); + } + } else { + begin() + lbry.getCostInfo(uri).then(resolve) + } } } diff --git a/ui/js/actions/search.js b/ui/js/actions/search.js index b2748ff1b..8dd85d822 100644 --- a/ui/js/actions/search.js +++ b/ui/js/actions/search.js @@ -6,6 +6,7 @@ import { } from 'actions/content' import { doNavigate, + doHistoryPush } from 'actions/app' import { selectCurrentPage, @@ -29,6 +30,8 @@ export function doSearch(query) { if(page != 'search') { dispatch(doNavigate('search', { query: query })) + } else { + dispatch(doHistoryPush({ query }, "Search for " + query, '/search')) } lighthouse.search(query).then(results => { diff --git a/ui/js/actions/settings.js b/ui/js/actions/settings.js new file mode 100644 index 000000000..18e3a5004 --- /dev/null +++ b/ui/js/actions/settings.js @@ -0,0 +1,31 @@ +import * as types from 'constants/action_types' +import lbry from 'lbry' + +export function doFetchDaemonSettings() { + return function(dispatch, getState) { + lbry.get_settings().then((settings) => { + dispatch({ + type: types.DAEMON_SETTINGS_RECEIVED, + data: { + settings + } + }) + }) + } +} + +export function doSetDaemonSetting(key, value) { + return function(dispatch, getState) { + let settings = {}; + settings[key] = value; + lbry.settings_set(settings).then(settings) + lbry.get_settings().then((settings) => { + dispatch({ + type: types.DAEMON_SETTINGS_RECEIVED, + data: { + settings + } + }) + }) + } +} \ No newline at end of file diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index c238f36b8..c3628821d 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -29,7 +29,7 @@ import { doDeleteFile, } from 'actions/file_info' import { - doWatchVideo, + doPurchaseUri, doLoadVideo, } from 'actions/content' import FileActions from './view' @@ -57,7 +57,7 @@ const perform = (dispatch) => ({ openInShell: (fileInfo) => dispatch(doOpenFileInShell(fileInfo)), deleteFile: (fileInfo, deleteFromComputer) => dispatch(doDeleteFile(fileInfo, deleteFromComputer)), openModal: (modal) => dispatch(doOpenModal(modal)), - startDownload: (uri) => dispatch(doWatchVideo(uri)), + startDownload: (uri) => dispatch(doPurchaseUri(uri)), loadVideo: (uri) => dispatch(doLoadVideo(uri)) }) diff --git a/ui/js/component/fileCard/view.jsx b/ui/js/component/fileCard/view.jsx index 371a955e6..1b721a703 100644 --- a/ui/js/component/fileCard/view.jsx +++ b/ui/js/component/fileCard/view.jsx @@ -70,7 +70,7 @@ class FileCard extends React.Component {
{title}
- + { !isResolvingUri && }
diff --git a/ui/js/component/filePrice/index.js b/ui/js/component/filePrice/index.js index 62b917b76..4c8bf9b7a 100644 --- a/ui/js/component/filePrice/index.js +++ b/ui/js/component/filePrice/index.js @@ -21,7 +21,7 @@ const makeSelect = () => { const perform = (dispatch) => ({ fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)), - cancelFetchCostInfo: (uri) => dispatch(doCancelFetchCostInfoForUri(uri)) + // cancelFetchCostInfo: (uri) => dispatch(doCancelFetchCostInfoForUri(uri)) }) export default connect(makeSelect, perform)(FilePrice) diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx index a6d5f988b..53dec32ef 100644 --- a/ui/js/component/router/view.jsx +++ b/ui/js/component/router/view.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import SettingsPage from 'page/settings.js'; +import SettingsPage from 'page/settings'; import HelpPage from 'page/help'; import ReportPage from 'page/report.js'; import StartPage from 'page/start.js'; diff --git a/ui/js/component/video/index.js b/ui/js/component/video/index.js index f7f6b9198..5566da840 100644 --- a/ui/js/component/video/index.js +++ b/ui/js/component/video/index.js @@ -9,7 +9,7 @@ import { selectCurrentModal, } from 'selectors/app' import { - doWatchVideo, + doPurchaseUri, doLoadVideo, } from 'actions/content' import { @@ -47,7 +47,7 @@ const makeSelect = () => { const perform = (dispatch) => ({ loadVideo: (uri) => dispatch(doLoadVideo(uri)), - watchVideo: (uri) => dispatch(doWatchVideo(uri)), + purchaseUri: (uri) => dispatch(doPurchaseUri(uri)), closeModal: () => dispatch(doCloseModal()), }) diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index 447d87d15..e4502f8d2 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -10,6 +10,15 @@ class VideoPlayButton extends React.Component { this.props.loadVideo(this.props.uri) } + onWatchClick() { + console.log(this.props) + this.props.purchaseUri(this.props.uri).then(() => { + if (!this.props.modal) { + this.props.startPlaying() + } + }) + } + render() { const { button, @@ -42,7 +51,7 @@ class VideoPlayButton extends React.Component { label={label ? label : ""} className="video__play-button" icon="icon-play" - onClick={onWatchClick} /> + onClick={this.onWatchClick} /> {modal} You don't have enough LBRY credits to pay for this stream. @@ -71,16 +80,6 @@ class Video extends React.Component { this.state = { isPlaying: false } } - onWatchClick() { - this.props.watchVideo(this.props.uri).then(() => { - if (!this.props.modal) { - this.setState({ - isPlaying: true - }) - } - }) - } - startPlaying() { this.setState({ isPlaying: true @@ -100,9 +99,6 @@ class Video extends React.Component { const isReadyToPlay = fileInfo && fileInfo.written_bytes > 0 - console.log('video render') - console.log(this.props) - let loadStatusMessage = '' if (isLoading) { @@ -112,40 +108,45 @@ class Video extends React.Component { } return ( -
{ - isPlaying ? +
{ + isPlaying || isReadyToPlay ? (!isReadyToPlay ? this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
: - ) : + ) :
- +
}
); } } -class VideoPlayer extends React.PureComponent { +class VideoPlayer extends React.Component { componentDidMount() { const elem = this.refs.video const { + autoplay, downloadPath, contentType, } = this.props const players = plyr.setup(elem) - players[0].play() + if (autoplay) { + players[0].play() + } } render() { const { downloadPath, contentType, + poster, } = this.props + // + return ( -
diff --git a/ui/js/reducers/settings.js b/ui/js/reducers/settings.js new file mode 100644 index 000000000..68c684f7e --- /dev/null +++ b/ui/js/reducers/settings.js @@ -0,0 +1,16 @@ +import * as types from 'constants/action_types' + +const reducers = {} +const defaultState = {} + +reducers[types.DAEMON_SETTINGS_RECEIVED] = function(state, action) { + return Object.assign({}, state, { + daemonSettings: action.data.settings + }) +} + +export default function reducer(state = defaultState, action) { + const handler = reducers[action.type]; + if (handler) return handler(state, action); + return state; +} diff --git a/ui/js/selectors/settings.js b/ui/js/selectors/settings.js new file mode 100644 index 000000000..850259043 --- /dev/null +++ b/ui/js/selectors/settings.js @@ -0,0 +1,20 @@ +import { + createSelector, +} from 'reselect' + +const _selectState = state => state.settings || {} + +export const selectDaemonSettings = createSelector( + _selectState, + (state) => state.daemonSettings || {} +) + +export const selectClientSettings = createSelector( + _selectState, + (state) => state.clientSettings +) + +export const selectSettingsIsGenerous = createSelector( + selectDaemonSettings, + (settings) => settings && settings.is_generous_host +) \ No newline at end of file diff --git a/ui/js/store.js b/ui/js/store.js index 7ab606258..479fdb49d 100644 --- a/ui/js/store.js +++ b/ui/js/store.js @@ -13,6 +13,7 @@ import costInfoReducer from 'reducers/cost_info' import fileInfoReducer from 'reducers/file_info' import rewardsReducer from 'reducers/rewards' import searchReducer from 'reducers/search' +import settingsReducer from 'reducers/settings' import walletReducer from 'reducers/wallet' function isFunction(object) { @@ -54,6 +55,7 @@ const reducers = redux.combineReducers({ costInfo: costInfoReducer, rewards: rewardsReducer, search: searchReducer, + settings: settingsReducer, wallet: walletReducer, }); diff --git a/ui/scss/component/_video.scss b/ui/scss/component/_video.scss index 9dd95ebe9..739dc1b26 100644 --- a/ui/scss/component/_video.scss +++ b/ui/scss/component/_video.scss @@ -3,6 +3,9 @@ video { box-sizing: border-box; max-height: 100%; max-width: 100%; + background-size: contain; + background-position: center center; + background-repeat: no-repeat; } .video { @@ -15,6 +18,7 @@ video { max-width: $width-page-constrained; max-height: $height-video-embedded; height: $height-video-embedded; + position: relative; /*for .plyr below*/ video { height: 100%; } @@ -24,6 +28,10 @@ video { &.video--active { /*background: none;*/ } + .plyr { + top: 50%; + transform: translateY(-50%); + } } .video__cover { From 900c5cbc2bdcbbab768d0d246ab6a61925f72468 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Thu, 18 May 2017 13:58:28 -0400 Subject: [PATCH 16/18] some progress towards cost and file info refactor, plus other fixes --- ui/js/actions/content.js | 76 +++--------- ui/js/actions/cost_info.js | 32 +++-- ui/js/actions/file_info.js | 77 ++++++++++-- ui/js/component/auth.js | 2 +- ui/js/component/fileActions/view.jsx | 3 - ui/js/component/fileCard/index.js | 1 - ui/js/component/fileCard/view.jsx | 23 +++- ui/js/component/filePrice/index.js | 1 + ui/js/component/filePrice/view.jsx | 2 +- ui/js/component/fileTile/view.jsx | 27 ----- ui/js/component/video/view.jsx | 9 +- ui/js/constants/action_types.js | 3 + ui/js/lbry.js | 157 ------------------------- ui/js/main.js | 4 + ui/js/page/fileListDownloaded/index.js | 6 +- ui/js/page/publish/view.jsx | 2 +- ui/js/page/showPage/view.jsx | 2 + ui/js/reducers/claims.js | 13 +- ui/js/reducers/content.js | 45 +------ ui/js/reducers/file_info.js | 124 +++++++++++-------- ui/js/selectors/content.js | 26 ---- ui/js/selectors/file_info.js | 58 +++++++-- 22 files changed, 274 insertions(+), 419 deletions(-) diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index a565b6e22..9b98483b9 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -57,66 +57,9 @@ export function doResolveUri(uri) { export function doCancelResolveUri(uri) { return function(dispatch, getState) { lbry.cancelResolve({ uri }) - } -} - -export function doFetchDownloadedContent() { - return function(dispatch, getState) { - const state = getState() - dispatch({ - type: types.FETCH_DOWNLOADED_CONTENT_STARTED, - }) - - lbry.claim_list_mine().then((myClaimInfos) => { - lbry.file_list().then((fileInfos) => { - const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); - - fileInfos.forEach(fileInfo => { - const uri = lbryuri.build({ - channelName: fileInfo.channel_name, - contentName: fileInfo.name, - }) - const claim = selectClaimsByUri(state)[uri] - if (!claim) dispatch(doResolveUri(uri)) - }) - - dispatch({ - type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, - data: { - fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), - } - }) - }); - }); - } -} - -export function doFetchPublishedContent() { - return function(dispatch, getState) { - const state = getState() - - dispatch({ - type: types.FETCH_PUBLISHED_CONTENT_STARTED, - }) - - lbry.claim_list_mine().then((claimInfos) => { - dispatch({ - type: types.FETCH_MY_CLAIMS_COMPLETED, - data: { - claims: claimInfos, - } - }) - lbry.file_list().then((fileInfos) => { - const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout) - - dispatch({ - type: types.FETCH_PUBLISHED_CONTENT_COMPLETED, - data: { - fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), - } - }) - }) + type: types.RESOLVE_URI_CANCELED, + data: { uri } }) } } @@ -142,10 +85,18 @@ export function doFetchFeaturedUris() { dispatch({ type: types.FETCH_FEATURED_CONTENT_COMPLETED, data: { - categories: Categories, - uris: featuredUris, + categories: ["FOO"], + uris: { FOO: ["lbry://gtasoc"]}, } }) + + // dispatch({ + // type: types.FETCH_FEATURED_CONTENT_COMPLETED, + // data: { + // categories: Categories, + // uris: featuredUris, + // } + // }) } const failure = () => { @@ -182,6 +133,7 @@ export function doUpdateLoadStatus(uri, outpoint) { type: types.DOWNLOADING_COMPLETED, data: { uri, + outpoint, fileInfo, } }) @@ -197,6 +149,7 @@ export function doUpdateLoadStatus(uri, outpoint) { type: types.DOWNLOADING_PROGRESSED, data: { uri, + outpoint, fileInfo, progress, } @@ -216,6 +169,7 @@ export function doDownloadFile(uri, streamInfo) { type: types.DOWNLOADING_STARTED, data: { uri, + outpoint: streamInfo.outpoint, fileInfo, } }) diff --git a/ui/js/actions/cost_info.js b/ui/js/actions/cost_info.js index b0f6af6d7..79ff4bdd5 100644 --- a/ui/js/actions/cost_info.js +++ b/ui/js/actions/cost_info.js @@ -1,6 +1,12 @@ import * as types from 'constants/action_types' import lbry from 'lbry' import lbryio from 'lbryio' +import { + doResolveUri +} from 'actions/content' +import { + selectResolvingUris, +} from 'selectors/content' import { selectClaimsByUri } from 'selectors/claims' @@ -12,21 +18,23 @@ export function doFetchCostInfoForUri(uri) { return function(dispatch, getState) { const state = getState(), claim = selectClaimsByUri(state)[uri], + isResolving = selectResolvingUris(state).indexOf(uri) !== -1, isGenerous = selectSettingsIsGenerous(state) - // - // function getCostGenerous(uri) { - // console.log('get cost generous: ' + uri) - // // If generous is on, the calculation is simple enough that we might as well do it here in the front end - // lbry.resolve({uri: uri}).then((resolutionInfo) => { - // console.log('resolve inside getCostGenerous ' + uri) - // console.log(resolutionInfo) - // if (!resolutionInfo) { - // return reject(new Error("Unused URI")); - // } + if (claim === null) { //claim doesn't exist, nothing to fetch a cost for + return + } + + if (!claim) { + setTimeout(() => { + dispatch(doFetchCostInfoForUri(uri)) + }, 1000) + if (!isResolving) { + dispatch(doResolveUri(uri)) + } + return + } - // }); - // } function begin() { dispatch({ diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index f7d2b08f3..8a187c2a4 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -4,6 +4,8 @@ import { selectClaimsByUri, } from 'selectors/claims' import { + selectIsFileListPending, + selectAllFileInfos, selectLoadingByUri, } from 'selectors/file_info' import { @@ -25,7 +27,6 @@ export function doFetchFileInfo(uri) { dispatch({ type: types.FETCH_FILE_INFO_STARTED, data: { - uri, outpoint, } }) @@ -34,7 +35,7 @@ export function doFetchFileInfo(uri) { dispatch({ type: types.FETCH_FILE_INFO_COMPLETED, data: { - uri, + outpoint, fileInfo, } }) @@ -43,6 +44,28 @@ export function doFetchFileInfo(uri) { } } +export function doFileList(uri) { + return function(dispatch, getState) { + const state = getState() + const isPending = selectIsFileListPending(state) + + if (!isPending) { + dispatch({ + type: types.FILE_LIST_STARTED, + }) + + lbry.file_list().then((fileInfos) => { + dispatch({ + type: types.FILE_LIST_COMPLETED, + data: { + fileInfos, + } + }) + }) + } + } +} + export function doOpenFileInShell(fileInfo) { return function(dispatch, getState) { shell.openItem(fileInfo.download_path) @@ -80,26 +103,56 @@ export function doDeleteFile(uri, fileInfo, deleteFromComputer) { } } + export function doFetchDownloadedContent() { return function(dispatch, getState) { - const state = getState() + const state = getState(), + fileInfos = selectAllFileInfos(state) dispatch({ type: types.FETCH_DOWNLOADED_CONTENT_STARTED, }) lbry.claim_list_mine().then((myClaimInfos) => { - lbry.file_list().then((fileInfos) => { - const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); - dispatch({ - type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, - data: { - fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), - } - }) - }); + const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); + + dispatch({ + type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, + data: { + fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), + } + }) }); } } +export function doFetchPublishedContent() { + return function(dispatch, getState) { + const state = getState(), + fileInfos = selectAllFileInfos(state) + + dispatch({ + type: types.FETCH_PUBLISHED_CONTENT_STARTED, + }) + + lbry.claim_list_mine().then((claimInfos) => { + dispatch({ + type: types.FETCH_MY_CLAIMS_COMPLETED, + data: { + claims: claimInfos, + } + }) + + const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout) + + dispatch({ + type: types.FETCH_PUBLISHED_CONTENT_COMPLETED, + data: { + fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), + } + }) + }) + } +} + diff --git a/ui/js/component/auth.js b/ui/js/component/auth.js index 261b065b1..7b934f339 100644 --- a/ui/js/component/auth.js +++ b/ui/js/component/auth.js @@ -200,7 +200,7 @@ const CodeRequiredStage = React.createClass({ }) if (!this.state.address) { - lbry.getUnusedAddress((address) => { + lbry.wallet_unused_address().then((address) => { setLocal('wallet_address', address); this.setState({ address: address }); }); diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index ec2b93587..3f7c7561a 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -72,9 +72,6 @@ class FileActions extends React.Component { let content - console.log('file actions render') - console.log(this.props) - if (!fileInfo && isAvailable === undefined) { content = diff --git a/ui/js/component/fileCard/index.js b/ui/js/component/fileCard/index.js index e3e11057e..89ebc5040 100644 --- a/ui/js/component/fileCard/index.js +++ b/ui/js/component/fileCard/index.js @@ -34,7 +34,6 @@ const makeSelect = () => { claim: selectClaimForUri(state, props), fileInfo: selectFileInfoForUri(state, props), obscureNsfw: selectObscureNsfw(state), - hasSignature: false, metadata: selectMetadataForUri(state, props), isResolvingUri: selectResolvingUri(state, props), }) diff --git a/ui/js/component/fileCard/view.jsx b/ui/js/component/fileCard/view.jsx index 1b721a703..918476a53 100644 --- a/ui/js/component/fileCard/view.jsx +++ b/ui/js/component/fileCard/view.jsx @@ -2,12 +2,12 @@ import React from 'react'; import lbry from 'lbry.js'; import lbryuri from 'lbryuri.js'; import Link from 'component/link'; -import {Thumbnail, TruncatedText,} from 'component/common'; +import {Thumbnail, TruncatedText, Icon} from 'component/common'; import FilePrice from 'component/filePrice' import UriIndicator from 'component/uriIndicator'; class FileCard extends React.Component { - componentDidMount() { + componentWillMount() { this.resolve(this.props) } @@ -29,7 +29,15 @@ class FileCard extends React.Component { } componentWillUnmount() { - this.props.cancelResolveUri(this.props.uri) + const { + isResolvingUri, + cancelResolveUri, + uri + } = this.props + + if (isResolvingUri) { + cancelResolveUri(uri) + } } handleMouseOver() { @@ -47,6 +55,8 @@ class FileCard extends React.Component { render() { const { + claim, + fileInfo, metadata, isResolvingUri, navigate, @@ -61,6 +71,8 @@ class FileCard extends React.Component { description = "Loading..." } else if (metadata && metadata.description) { description = metadata.description + } else if (claim === null) { + description = 'This address contains no content.' } return ( @@ -70,7 +82,10 @@ class FileCard extends React.Component {
{title}
- { !isResolvingUri && } + + + { fileInfo ? {' '} : '' } +
diff --git a/ui/js/component/filePrice/index.js b/ui/js/component/filePrice/index.js index 4c8bf9b7a..726ceb3ee 100644 --- a/ui/js/component/filePrice/index.js +++ b/ui/js/component/filePrice/index.js @@ -12,6 +12,7 @@ import FilePrice from './view' const makeSelect = () => { const selectCostInfoForUri = makeSelectCostInfoForUri() + const select = (state, props) => ({ costInfo: selectCostInfoForUri(state, props), }) diff --git a/ui/js/component/filePrice/view.jsx b/ui/js/component/filePrice/view.jsx index 56174c8a2..4edc3a3e7 100644 --- a/ui/js/component/filePrice/view.jsx +++ b/ui/js/component/filePrice/view.jsx @@ -4,7 +4,7 @@ import { } from 'component/common' class FilePrice extends React.Component{ - componentDidMount() { + componentWillMount() { this.fetchCost(this.props) } diff --git a/ui/js/component/fileTile/view.jsx b/ui/js/component/fileTile/view.jsx index c015c6327..250bf6296 100644 --- a/ui/js/component/fileTile/view.jsx +++ b/ui/js/component/fileTile/view.jsx @@ -13,11 +13,8 @@ class FileTile extends React.Component { constructor(props) { super(props) - this._fileInfoSubscribeId = null - this._isMounted = null this.state = { showNsfwHelp: false, - isHidden: false, } } @@ -29,31 +26,11 @@ class FileTile extends React.Component { uri, } = this.props - this._isMounted = true; - - if (this.props.hideOnRemove) { - this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate); - } - if(!isResolvingUri && !claim && uri) { resolveUri(uri) } } - componentWillUnmount() { - if (this._fileInfoSubscribeId) { - lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId); - } - } - - onFileInfoUpdate(fileInfo) { - if (!fileInfo && this._isMounted && this.props.hideOnRemove) { - this.setState({ - isHidden: true - }); - } - } - handleMouseOver() { if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) { this.setState({ @@ -71,10 +48,6 @@ class FileTile extends React.Component { } render() { - if (this.state.isHidden) { - return null; - } - const { claim, metadata, diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index e4502f8d2..3559a728e 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -11,7 +11,7 @@ class VideoPlayButton extends React.Component { } onWatchClick() { - console.log(this.props) + console.log(this) this.props.purchaseUri(this.props.uri).then(() => { if (!this.props.modal) { this.props.startPlaying() @@ -24,7 +24,6 @@ class VideoPlayButton extends React.Component { button, label, className, - onWatchClick, metadata, metadata: { title, @@ -51,7 +50,7 @@ class VideoPlayButton extends React.Component { label={label ? label : ""} className="video__play-button" icon="icon-play" - onClick={this.onWatchClick} /> + onClick={this.onWatchClick.bind(this)} /> {modal} You don't have enough LBRY credits to pay for this stream. @@ -142,11 +141,9 @@ class VideoPlayer extends React.Component { poster, } = this.props - // - return ( ) } diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index a12b9ad8f..2d548bc48 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -35,8 +35,11 @@ export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED' export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED' export const RESOLVE_URI_STARTED = 'RESOLVE_URI_STARTED' export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED' +export const RESOLVE_URI_CANCELED = 'RESOLVE_URI_CANCELED' export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED' export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED' +export const FILE_LIST_STARTED = 'FILE_LIST_STARTED' +export const FILE_LIST_COMPLETED = 'FILE_LIST_COMPLETED' export const FETCH_DOWNLOADED_CONTENT_STARTED = 'FETCH_DOWNLOADED_CONTENT_STARTED' export const FETCH_DOWNLOADED_CONTENT_COMPLETED = 'FETCH_DOWNLOADED_CONTENT_COMPLETED' export const FETCH_PUBLISHED_CONTENT_STARTED = 'FETCH_PUBLISHED_CONTENT_STARTED' diff --git a/ui/js/lbry.js b/ui/js/lbry.js index cb00c1560..ad7e7b6bd 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -151,14 +151,6 @@ lbry.isDaemonAcceptingConnections = function (callback) { lbry.call('status', {}, () => callback(true), null, () => callback(false)) }; -lbry.checkFirstRun = function(callback) { - lbry.call('is_first_run', {}, callback); -} - -lbry.getUnusedAddress = function(callback) { - lbry.call('wallet_unused_address', {}, callback); -} - lbry.checkAddressIsMine = function(address, callback) { lbry.call('address_is_mine', {address: address}, callback); } @@ -167,108 +159,12 @@ lbry.sendToAddress = function(amount, address, callback, errorCallback) { lbry.call("send_amount_to_address", { "amount" : amount, "address": address }, callback, errorCallback); } -lbry.getClaimInfo = function(name, callback) { - if (!name) { - throw new Error(`Name required.`); - } - lbry.call('get_claim_info', { name: name }, callback); -} - lbry.getMyClaim = function(name, callback) { lbry.call('claim_list_mine', {}, (claims) => { callback(claims.find((claim) => claim.name == name) || null); }); } -lbry.getPeersForBlobHash = function(blobHash, callback) { - let timedOut = false; - const timeout = setTimeout(() => { - timedOut = true; - callback([]); - }, lbry.peerListTimeout); - - lbry.call('peer_list', { blob_hash: blobHash }, function(peers) { - if (!timedOut) { - clearTimeout(timeout); - callback(peers); - } - }); -} -// -// lbry.costPromiseCache = {} -// lbry.getCostInfo = function(uri) { -// if (lbry.costPromiseCache[uri] === undefined) { -// lbry.costPromiseCache[uri] = new Promise((resolve, reject) => { -// const COST_INFO_CACHE_KEY = 'cost_info_cache'; -// let costInfoCache = getSession(COST_INFO_CACHE_KEY, {}) -// -// function cacheAndResolve(cost, includesData) { -// console.log('getCostInfo cacheAndResolve ' + uri) -// console.log(cost) -// costInfoCache[uri] = {cost, includesData}; -// setSession(COST_INFO_CACHE_KEY, costInfoCache); -// resolve({cost, includesData}); -// } -// -// if (!uri) { -// return reject(new Error(`URI required.`)); -// } -// -// if (costInfoCache[uri] && costInfoCache[uri].cost) { -// return resolve(costInfoCache[uri]) -// } -// -// function getCost(uri, size) { -// lbry.stream_cost_estimate({uri, ... size !== null ? {size} : {}}).then((cost) => { -// cacheAndResolve(cost, size !== null); -// }, reject); -// } -// -// function getCostGenerous(uri) { -// console.log('get cost generous: ' + uri) -// // If generous is on, the calculation is simple enough that we might as well do it here in the front end -// lbry.resolve({uri: uri}).then((resolutionInfo) => { -// console.log('resolve inside getCostGenerous ' + uri) -// console.log(resolutionInfo) -// if (!resolutionInfo) { -// return reject(new Error("Unused URI")); -// } -// const fee = resolutionInfo.claim.value.stream.metadata.fee; -// if (fee === undefined) { -// cacheAndResolve(0, true); -// } else if (fee.currency == 'LBC') { -// cacheAndResolve(fee.amount, true); -// } else { -// lbryio.getExchangeRates().then(({lbc_usd}) => { -// cacheAndResolve(fee.amount / lbc_usd, true); -// }); -// } -// }); -// } -// -// const uriObj = lbryuri.parse(uri); -// const name = uriObj.path || uriObj.name; -// -// lbry.settings_get({allow_cached: true}).then(({is_generous_host}) => { -// if (is_generous_host) { -// return getCostGenerous(uri); -// } -// -// lighthouse.get_size_for_name(name).then((size) => { -// if (size) { -// getCost(name, size); -// } -// else { -// getCost(name, null); -// } -// }, () => { -// getCost(name, null); -// }); -// }); -// }); -// } -// return lbry.costPromiseCache[uri]; -// } /** * Takes a LBRY URI; will first try and calculate a total cost using * Lighthouse. If Lighthouse can't be reached, it just retrives the @@ -287,8 +183,6 @@ lbry.getCostInfo = function(uri) { let costInfoCache = getSession(COST_INFO_CACHE_KEY, {}) function cacheAndResolve(cost, includesData) { - console.log('getCostInfo cacheAndResolve ' + uri) - console.log(cost) costInfoCache[uri] = {cost, includesData}; setSession(COST_INFO_CACHE_KEY, costInfoCache); resolve({cost, includesData}); @@ -509,10 +403,7 @@ lbry.stop = function(callback) { lbry.call('stop', {}, callback); }; -lbry.fileInfo = {}; lbry._subscribeIdCount = 0; -lbry._fileInfoSubscribeCallbacks = {}; -lbry._fileInfoSubscribeInterval = 500000; lbry._balanceSubscribeCallbacks = {}; lbry._balanceSubscribeInterval = 5000; lbry._removedFiles = []; @@ -527,54 +418,6 @@ lbry._updateClaimOwnershipCache = function(claimId) { }; -lbry._updateFileInfoSubscribers = function(outpoint) { - const callSubscribedCallbacks = (outpoint, fileInfo) => { - for (let callback of Object.values(this._fileInfoSubscribeCallbacks[outpoint])) { - callback(fileInfo); - } - } - - if (lbry._removedFiles.includes(outpoint)) { - callSubscribedCallbacks(outpoint, false); - } else { - lbry.file_list({ - outpoint: outpoint, - full_status: true, - }).then(([fileInfo]) => { - if (fileInfo) { - if (this._claimIdOwnershipCache[fileInfo.claim_id] === undefined) { - this._updateClaimOwnershipCache(fileInfo.claim_id); - } - fileInfo.isMine = !!this._claimIdOwnershipCache[fileInfo.claim_id]; - } - - callSubscribedCallbacks(outpoint, fileInfo); - }); - } - - if (Object.keys(this._fileInfoSubscribeCallbacks[outpoint]).length) { - setTimeout(() => { - this._updateFileInfoSubscribers(outpoint); - }, lbry._fileInfoSubscribeInterval); - } -} - -lbry.fileInfoSubscribe = function(outpoint, callback) { - if (!lbry._fileInfoSubscribeCallbacks[outpoint]) - { - lbry._fileInfoSubscribeCallbacks[outpoint] = {}; - } - - const subscribeId = ++lbry._subscribeIdCount; - lbry._fileInfoSubscribeCallbacks[outpoint][subscribeId] = callback; - lbry._updateFileInfoSubscribers(outpoint); - return subscribeId; -} - -lbry.fileInfoUnsubscribe = function(outpoint, subscribeId) { - delete lbry._fileInfoSubscribeCallbacks[outpoint][subscribeId]; -} - lbry._balanceUpdateInterval = null; lbry._updateBalanceSubscribers = function() { lbry.get_balance().then(function(balance) { diff --git a/ui/js/main.js b/ui/js/main.js index d4bc2c273..a52e4b943 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -17,6 +17,9 @@ import { import { doFetchDaemonSettings } from 'actions/settings' +import { + doFileList +} from 'actions/file_info' import parseQueryParams from 'util/query_params' const {remote, ipcRenderer} = require('electron'); @@ -56,6 +59,7 @@ var init = function() { window.sessionStorage.setItem('loaded', 'y'); //once we've made it here once per session, we don't need to show splash again app.store.dispatch(doHistoryPush({}, "Discover", "/discover")) app.store.dispatch(doFetchDaemonSettings()) + app.store.dispatch(doFileList()) ReactDOM.render(
{ lbryio.enabled ? : '' }
, canvas) } diff --git a/ui/js/page/fileListDownloaded/index.js b/ui/js/page/fileListDownloaded/index.js index 7ab01ab9c..7122ff5fd 100644 --- a/ui/js/page/fileListDownloaded/index.js +++ b/ui/js/page/fileListDownloaded/index.js @@ -4,12 +4,10 @@ import { } from 'react-redux' import { doFetchDownloadedContent, -} from 'actions/content' -import { - selectFetchingDownloadedContent, -} from 'selectors/content' +} from 'actions/file_info' import { selectDownloadedFileInfo, + selectFetchingDownloadedContent, } from 'selectors/file_info' import { doNavigate, diff --git a/ui/js/page/publish/view.jsx b/ui/js/page/publish/view.jsx index 7a6e4806f..cb0b152b6 100644 --- a/ui/js/page/publish/view.jsx +++ b/ui/js/page/publish/view.jsx @@ -100,7 +100,7 @@ var PublishPage = React.createClass({ }; if (this.state.isFee) { - lbry.getUnusedAddress((address) => { + lbry.wallet_unused_address().then((address) => { metadata.fee = {}; metadata.fee[this.state.feeCurrency] = { amount: parseFloat(this.state.feeAmount), diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx index c1358c446..0d0b0da5e 100644 --- a/ui/js/page/showPage/view.jsx +++ b/ui/js/page/showPage/view.jsx @@ -21,6 +21,8 @@ class ShowPage extends React.Component{ uri, } = props + console.log('show page resolve ' + uri) + console.log('isResolving: ' + isResolvingUri) if(!isResolvingUri && claim === undefined && uri) { resolveUri(uri) } diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index 683f52ef1..b8885d98a 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -14,9 +14,7 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { const newClaims = Object.assign({}, state.claimsByUri) - if (claim !== undefined) { - newClaims[uri] = claim - } + newClaims[uri] = claim //This needs a sanity boost... if (certificate !== undefined && claim === undefined) { @@ -32,6 +30,15 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { }) } +reducers[types.RESOLVE_URI_CANCELED] = function(state, action) { + const uri = action.data.uri + const newClaims = Object.assign({}, state.claimsByUri) + delete newClaims[uri] + return Object.assign({}, state, { + claimsByUri: newClaims + }) +} + reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) { const { uri, diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js index 8fee4c234..117b6c830 100644 --- a/ui/js/reducers/content.js +++ b/ui/js/reducers/content.js @@ -30,7 +30,7 @@ reducers[types.RESOLVE_URI_STARTED] = function(state, action) { const oldResolving = state.resolvingUris || [] const newResolving = Object.assign([], oldResolving) - if (newResolving.indexOf(uri) == -1) newResolving.push(uri) + if (newResolving.indexOf(uri) === -1) newResolving.push(uri) return Object.assign({}, state, { resolvingUris: newResolving @@ -48,51 +48,14 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { ...resolvingUris.slice(index + 1) ] - const newState = Object.assign({}, state, { + return Object.assign({}, state, { resolvingUris: newResolvingUris, }) - - return Object.assign({}, state, newState) } -reducers[types.FETCH_DOWNLOADED_CONTENT_STARTED] = function(state, action) { - return Object.assign({}, state, { - fetchingDownloadedContent: true, - }) -} -reducers[types.FETCH_DOWNLOADED_CONTENT_COMPLETED] = function(state, action) { - const { - fileInfos - } = action.data - const newDownloadedContent = Object.assign({}, state.downloadedContent, { - fileInfos - }) - - return Object.assign({}, state, { - downloadedContent: newDownloadedContent, - fetchingDownloadedContent: false, - }) -} - -reducers[types.FETCH_PUBLISHED_CONTENT_STARTED] = function(state, action) { - return Object.assign({}, state, { - fetchingPublishedContent: true, - }) -} - -reducers[types.FETCH_PUBLISHED_CONTENT_COMPLETED] = function(state, action) { - const { - fileInfos - } = action.data - const newPublishedContent = Object.assign({}, state.publishedContent, { - fileInfos - }) - - return Object.assign({}, state, { - publishedContent: newPublishedContent, - fetchingPublishedContent: false, - }) +reducers[types.RESOLVE_URI_CANCELED] = function(state, action) { + return reducers[types.RESOLVE_URI_COMPLETED](state, action) } export default function reducer(state = defaultState, action) { diff --git a/ui/js/reducers/file_info.js b/ui/js/reducers/file_info.js index 951b0f213..affd4103d 100644 --- a/ui/js/reducers/file_info.js +++ b/ui/js/reducers/file_info.js @@ -5,13 +5,35 @@ const reducers = {} const defaultState = { } +reducers[types.FILE_LIST_STARTED] = function(state, action) { + return Object.assign({}, state, { + isFileListPending: true, + }) +} + +reducers[types.FILE_LIST_COMPLETED] = function(state, action) { + const { + fileInfos, + } = action.data + + const newFileInfos = Object.assign({}, state.fileInfos) + fileInfos.forEach((fileInfo) => { + newFileInfos[fileInfo.outpoint] = fileInfo + }) + + return Object.assign({}, state, { + isFileListPending: false, + fileInfos: newFileInfos + }) +} + reducers[types.FETCH_FILE_INFO_STARTED] = function(state, action) { const { - uri, + outpoint } = action.data const newFetching = Object.assign({}, state.fetching) - newFetching[uri] = true + newFetching[outpoint] = true return Object.assign({}, state, { fetching: newFetching, @@ -20,19 +42,18 @@ reducers[types.FETCH_FILE_INFO_STARTED] = function(state, action) { reducers[types.FETCH_FILE_INFO_COMPLETED] = function(state, action) { const { - uri, fileInfo, + outpoint, } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) const newFetching = Object.assign({}, state.fetching) - newByUri[uri] = fileInfo || null - - delete newFetching[uri] + newFileInfos[outpoint] = fileInfo + delete newFetching[outpoint] return Object.assign({}, state, { - byUri: newByUri, + fileInfos: newFileInfos, fetching: newFetching, }) } @@ -40,9 +61,10 @@ reducers[types.FETCH_FILE_INFO_COMPLETED] = function(state, action) { reducers[types.DOWNLOADING_STARTED] = function(state, action) { const { uri, + outpoint, fileInfo, } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) const newDownloading = Object.assign({}, state.downloading) const newDownloadingByUri = Object.assign({}, newDownloading.byUri) const newLoading = Object.assign({}, state.loading) @@ -50,13 +72,13 @@ reducers[types.DOWNLOADING_STARTED] = function(state, action) { newDownloadingByUri[uri] = true newDownloading.byUri = newDownloadingByUri - newByUri[uri] = fileInfo + newFileInfos[outpoint] = fileInfo delete newLoadingByUri[uri] newLoading.byUri = newLoadingByUri return Object.assign({}, state, { downloading: newDownloading, - byUri: newByUri, + fileInfos: newFileInfos, loading: newLoading, }) } @@ -64,16 +86,17 @@ reducers[types.DOWNLOADING_STARTED] = function(state, action) { reducers[types.DOWNLOADING_PROGRESSED] = function(state, action) { const { uri, + outpoint, fileInfo, } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) const newDownloading = Object.assign({}, state.downloading) - newByUri[uri] = fileInfo + newFileInfos[outpoint] = fileInfo newDownloading[uri] = true return Object.assign({}, state, { - byUri: newByUri, + fileInfos: newByUri, downloading: newDownloading }) } @@ -81,31 +104,32 @@ reducers[types.DOWNLOADING_PROGRESSED] = function(state, action) { reducers[types.DOWNLOADING_COMPLETED] = function(state, action) { const { uri, + outpoint, fileInfo, } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) const newDownloading = Object.assign({}, state.downloading) const newDownloadingByUri = Object.assign({}, newDownloading.byUri) - newByUri[uri] = fileInfo + newFileInfos[outpoint] = fileInfo delete newDownloadingByUri[uri] newDownloading.byUri = newDownloadingByUri return Object.assign({}, state, { - byUri: newByUri, + fileInfos: newFileInfos, downloading: newDownloading, }) } reducers[types.DELETE_FILE_STARTED] = function(state, action) { const { - uri, + outpoint } = action.data const newDeleting = Object.assign({}, state.deleting) const newByUri = Object.assign({}, newDeleting.byUri) - newByUri[uri] = true - newDeleting.byUri = newByUri + newFileInfos[outpoint] = true + newDeleting.byUri = newFileInfos return Object.assign({}, state, { deleting: newDeleting, @@ -118,15 +142,15 @@ reducers[types.DELETE_FILE_COMPLETED] = function(state, action) { } = action.data const newDeleting = Object.assign({}, state.deleting) const newDeletingByUri = Object.assign({}, newDeleting.byUri) - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) delete newDeletingByUri[uri] newDeleting.byUri = newDeletingByUri - delete newByUri[uri] + delete newFileInfos[outpoint] return Object.assign({}, state, { deleting: newDeleting, - byUri: newByUri, + fileInfos: newFileInfos, }) } @@ -135,10 +159,10 @@ reducers[types.LOADING_VIDEO_STARTED] = function(state, action) { uri, } = action.data const newLoading = Object.assign({}, state.loading) - const newByUri = Object.assign({}, newLoading.byUri) + const newFileInfos = Object.assign({}, newLoading.byUri) - newByUri[uri] = true - newLoading.byUri = newByUri + newFileInfos[outpoint] = true + newLoading.byUri = newFileInfos return Object.assign({}, state, { loading: newLoading, @@ -150,33 +174,38 @@ reducers[types.LOADING_VIDEO_FAILED] = function(state, action) { uri, } = action.data const newLoading = Object.assign({}, state.loading) - const newByUri = Object.assign({}, newLoading.byUri) + const newFileInfos = Object.assign({}, newLoading.byUri) - delete newByUri[uri] - newLoading.byUri = newByUri + delete newFileInfos[outpoint] + newLoading.byUri = newFileInfos return Object.assign({}, state, { loading: newLoading, }) } +reducers[types.FETCH_DOWNLOADED_CONTENT_STARTED] = function(state, action) { + return Object.assign({}, state, { + fetchingDownloadedContent: true, + }) +} + reducers[types.FETCH_DOWNLOADED_CONTENT_COMPLETED] = function(state, action) { - const { - fileInfos, - } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) - fileInfos.forEach(fileInfo => { - const uri = lbryuri.build({ - channelName: fileInfo.channel_name, - contentName: fileInfo.name, - }) - - newByUri[uri] = fileInfo + action.data.fileInfos.forEach(fileInfo => { + newFileInfos[fileInfo.outpoint] = fileInfo }) return Object.assign({}, state, { - byUri: newByUri + fileInfos: newFileInfos, + fetchingDownloadedContent: false + }) +} + +reducers[types.FETCH_PUBLISHED_CONTENT_STARTED] = function(state, action) { + return Object.assign({}, state, { + fetchingPublishedContent: true, }) } @@ -184,23 +213,20 @@ reducers[types.FETCH_PUBLISHED_CONTENT_COMPLETED] = function(state, action) { const { fileInfos } = action.data - const newByUri = Object.assign({}, state.byUri) + const newFileInfos = Object.assign({}, state.fileInfos) fileInfos.forEach(fileInfo => { - const uri = lbryuri.build({ - channelName: fileInfo.channel_name, - contentName: fileInfo.name, - }) - - newByUri[uri] = fileInfo + newFileInfos[fileInfo.outpoint] = fileInfo }) return Object.assign({}, state, { - byUri: newByUri + fileInfos: newFileInfos, + fetchingPublishedContent: false }) } + export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js index 22476b229..61efa2e1f 100644 --- a/ui/js/selectors/content.js +++ b/ui/js/selectors/content.js @@ -16,32 +16,6 @@ export const selectFetchingFeaturedUris = createSelector( (state) => !!state.fetchingFeaturedContent ) - -export const selectFetchingDownloadedContent = createSelector( - _selectState, - (state) => !!state.fetchingDownloadedContent -) - -export const selectDownloadedContent = createSelector( - _selectState, - (state) => state.downloadedContent || {} -) - -export const selectDownloadedContentFileInfos = createSelector( - selectDownloadedContent, - (downloadedContent) => downloadedContent.fileInfos || [] -) - -export const selectFetchingPublishedContent = createSelector( - _selectState, - (state) => !!state.fetchingPublishedContent -) - -export const selectPublishedContent = createSelector( - _selectState, - (state) => state.publishedContent || {} -) - export const selectResolvingUris = createSelector( _selectState, (state) => state.resolvingUris || [] diff --git a/ui/js/selectors/file_info.js b/ui/js/selectors/file_info.js index 76fb0031d..c9104bbc2 100644 --- a/ui/js/selectors/file_info.js +++ b/ui/js/selectors/file_info.js @@ -2,14 +2,20 @@ import { createSelector, } from 'reselect' import { + selectClaimsByUri, selectMyClaimsOutpoints, } from 'selectors/claims' export const _selectState = state => state.fileInfo || {} -export const selectAllFileInfoByUri = createSelector( +export const selectIsFileListPending = createSelector( _selectState, - (state) => state.byUri || {} + (state) => state.isFileListPending +) + +export const selectAllFileInfos = createSelector( + _selectState, + (state) => state.fileInfos || {} ) export const selectDownloading = createSelector( @@ -22,8 +28,42 @@ export const selectDownloadingByUri = createSelector( (downloading) => downloading.byUri || {} ) +export const selectFetchingDownloadedContent = createSelector( + _selectState, + (state) => !!state.fetchingDownloadedContent +) + +export const selectDownloadedContent = createSelector( + _selectState, + (state) => state.downloadedContent || {} +) + +export const selectDownloadedContentFileInfos = createSelector( + selectDownloadedContent, + (downloadedContent) => downloadedContent.fileInfos || [] +) + +export const selectFetchingPublishedContent = createSelector( + _selectState, + (state) => !!state.fetchingPublishedContent +) + +export const selectPublishedContent = createSelector( + _selectState, + (state) => state.publishedContent || {} +) + export const selectFileInfoForUri = (state, props) => { - return selectAllFileInfoByUri(state)[props.uri] + const claims = selectClaimsByUri(state), + claim = claims[props.uri], + outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined + + console.log('select file info') + console.log(claims) + console.log(claim) + console.log(outpoint) + console.log(selectAllFileInfos(state)) + return outpoint ? selectAllFileInfos(state)[outpoint] : undefined } export const makeSelectFileInfoForUri = () => { @@ -68,23 +108,21 @@ export const makeSelectLoadingForUri = () => { } export const selectDownloadedFileInfo = createSelector( - selectAllFileInfoByUri, - (byUri) => { + selectAllFileInfos, + (fileInfos) => { const fileInfoList = [] - Object.keys(byUri).forEach(key => { - const fileInfo = byUri[key] - + Object.keys(fileInfos).forEach(outpoint => { + const fileInfo = fileInfos[outpoint] if (fileInfo.completed || fileInfo.written_bytes) { fileInfoList.push(fileInfo) } }) - return fileInfoList } ) export const selectPublishedFileInfo = createSelector( - selectAllFileInfoByUri, + selectAllFileInfos, selectMyClaimsOutpoints, (byUri, outpoints) => { const fileInfos = [] From 9d8fa102eeccdbd06c23cb3b812eba27b91e5be8 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Thu, 18 May 2017 19:14:26 -0400 Subject: [PATCH 17/18] bug fixes, file info and my claims refactor, list claims in channel --- ui/js/actions/app.js | 2 +- ui/js/actions/content.js | 45 +++++---- ui/js/actions/file_info.js | 111 ++++++++-------------- ui/js/component/fileActions/index.js | 6 +- ui/js/component/fileActions/view.jsx | 28 +++--- ui/js/component/fileList/view.jsx | 3 +- ui/js/component/video/view.jsx | 9 +- ui/js/constants/action_types.js | 10 +- ui/js/lbry.js | 125 +++++-------------------- ui/js/lbryuri.js | 5 + ui/js/main.js | 4 +- ui/js/page/channel/index.js | 26 +++-- ui/js/page/channel/view.jsx | 11 ++- ui/js/page/fileListDownloaded/index.js | 12 +-- ui/js/page/fileListDownloaded/view.jsx | 12 +-- ui/js/page/fileListPublished/index.js | 16 ++-- ui/js/page/fileListPublished/view.jsx | 14 +-- ui/js/page/filePage/view.jsx | 2 +- ui/js/page/help/view.jsx | 3 - ui/js/page/publish/index.js | 4 + ui/js/page/publish/view.jsx | 74 +++++++-------- ui/js/page/showPage/view.jsx | 7 +- ui/js/reducers/claims.js | 35 +++---- ui/js/reducers/file_info.js | 118 +++++------------------ ui/js/selectors/claims.js | 49 +++++----- ui/js/selectors/file_info.js | 113 +++++++++------------- 26 files changed, 331 insertions(+), 513 deletions(-) diff --git a/ui/js/actions/app.js b/ui/js/actions/app.js index c35042a90..8ede77fee 100644 --- a/ui/js/actions/app.js +++ b/ui/js/actions/app.js @@ -43,7 +43,6 @@ export function doChangePath(path) { path, } }) - } } @@ -58,6 +57,7 @@ export function doHistoryPush(params, title, relativeUrl) { let pathParts = window.location.pathname.split('/') pathParts[pathParts.length - 1] = relativeUrl.replace(/^\//, '') const url = pathParts.join('/') + title += " - LBRY" history.pushState(params, title, url) window.document.title = title } diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 9b98483b9..a3436fbbb 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -8,7 +8,7 @@ import { } from 'selectors/wallet' import { selectFileInfoForUri, - selectDownloadingByUri, + selectUrisDownloading, } from 'selectors/file_info' import { selectResolvingUris @@ -66,6 +66,7 @@ export function doCancelResolveUri(uri) { export function doFetchFeaturedUris() { return function(dispatch, getState) { + return const state = getState() dispatch({ @@ -81,22 +82,22 @@ export function doFetchFeaturedUris() { featuredUris[category] = Uris[category] } }) + // + // dispatch({ + // type: types.FETCH_FEATURED_CONTENT_COMPLETED, + // data: { + // categories: ["FOO"], + // uris: { FOO: ["lbry://gtasoc"]}, + // } + // }) dispatch({ type: types.FETCH_FEATURED_CONTENT_COMPLETED, data: { - categories: ["FOO"], - uris: { FOO: ["lbry://gtasoc"]}, + categories: Categories, + uris: featuredUris, } }) - - // dispatch({ - // type: types.FETCH_FEATURED_CONTENT_COMPLETED, - // data: { - // categories: Categories, - // uris: featuredUris, - // } - // }) } const failure = () => { @@ -219,7 +220,7 @@ export function doPurchaseUri(uri) { const balance = selectBalance(state) const fileInfo = selectFileInfoForUri(state, { uri }) const costInfo = selectCostInfoForUri(state, { uri }) - const downloadingByUri = selectDownloadingByUri(state) + const downloadingByUri = selectUrisDownloading(state) const alreadyDownloading = !!downloadingByUri[uri] const { cost } = costInfo @@ -268,18 +269,28 @@ export function doFetchClaimsByChannel(uri) { } = resolutionInfo ? resolutionInfo : { claims_in_channel: [] } dispatch({ - type: types.FETCH_CHANNEL_CLAIMS_STARTED, + type: types.FETCH_CHANNEL_CLAIMS_COMPLETED, data: { uri, claims: claims_in_channel } }) - }).catch(() => { + }) + } +} + +export function doClaimListMine() { + return function(dispatch, getState) { + dispatch({ + type: types.CLAIM_LIST_MINE_STARTED + }) + + + lbry.claim_list_mine().then((claims) => { dispatch({ - type: types.FETC, + type: types.CLAIM_LIST_MINE_COMPLETED, data: { - uri, - claims: [] + claims } }) }) diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js index 8a187c2a4..23ba50e71 100644 --- a/ui/js/actions/file_info.js +++ b/ui/js/actions/file_info.js @@ -1,12 +1,16 @@ import * as types from 'constants/action_types' import lbry from 'lbry' +import { + doClaimListMine +} from 'actions/content' import { selectClaimsByUri, + selectClaimListMineIsPending, } from 'selectors/claims' import { - selectIsFileListPending, + selectFileListIsPending, selectAllFileInfos, - selectLoadingByUri, + selectUrisLoading, } from 'selectors/file_info' import { doCloseModal, @@ -21,7 +25,7 @@ export function doFetchFileInfo(uri) { const state = getState() const claim = selectClaimsByUri(state)[uri] const outpoint = claim ? `${claim.txid}:${claim.nout}` : null - const alreadyFetching = !!selectLoadingByUri(state)[uri] + const alreadyFetching = !!selectUrisLoading(state)[uri] if (!alreadyFetching) { dispatch({ @@ -31,12 +35,13 @@ export function doFetchFileInfo(uri) { } }) - lbry.file_list({outpoint: outpoint, full_status: true}).then(([fileInfo]) => { + lbry.file_list({outpoint: outpoint, full_status: true}).then(fileInfos => { + dispatch({ type: types.FETCH_FILE_INFO_COMPLETED, data: { outpoint, - fileInfo, + fileInfo: fileInfos && fileInfos.length ? fileInfos[0] : null, } }) }) @@ -44,10 +49,10 @@ export function doFetchFileInfo(uri) { } } -export function doFileList(uri) { +export function doFileList() { return function(dispatch, getState) { const state = getState() - const isPending = selectIsFileListPending(state) + const isPending = selectFileListIsPending(state) if (!isPending) { dispatch({ @@ -78,81 +83,39 @@ export function doOpenFileInFolder(fileInfo) { } } -export function doDeleteFile(uri, fileInfo, deleteFromComputer) { +export function doDeleteFile(outpoint, deleteFromComputer) { return function(dispatch, getState) { + dispatch({ - type: types.DELETE_FILE_STARTED, + type: types.FILE_DELETE, data: { - uri, - fileInfo, - deleteFromComputer, + outpoint } }) - const successCallback = () => { - dispatch({ - type: types.DELETE_FILE_COMPLETED, - data: { - uri, - } - }) - dispatch(doCloseModal()) + lbry.file_delete({ + outpoint: outpoint, + delete_target_file: deleteFromComputer, + }) + + dispatch(doCloseModal()) + } +} + + +export function doFetchFileInfosAndPublishedClaims() { + return function(dispatch, getState) { + const state = getState(), + isClaimListMinePending = selectClaimListMineIsPending(state), + isFileInfoListPending = selectFileListIsPending(state) + + if (isClaimListMinePending === undefined) { + dispatch(doClaimListMine()) } - lbry.removeFile(fileInfo.outpoint, deleteFromComputer, successCallback) - } -} - - -export function doFetchDownloadedContent() { - return function(dispatch, getState) { - const state = getState(), - fileInfos = selectAllFileInfos(state) - - dispatch({ - type: types.FETCH_DOWNLOADED_CONTENT_STARTED, - }) - - lbry.claim_list_mine().then((myClaimInfos) => { - - const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); - - dispatch({ - type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, - data: { - fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), - } - }) - }); - } -} - -export function doFetchPublishedContent() { - return function(dispatch, getState) { - const state = getState(), - fileInfos = selectAllFileInfos(state) - - dispatch({ - type: types.FETCH_PUBLISHED_CONTENT_STARTED, - }) - - lbry.claim_list_mine().then((claimInfos) => { - dispatch({ - type: types.FETCH_MY_CLAIMS_COMPLETED, - data: { - claims: claimInfos, - } - }) - - const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout) - - dispatch({ - type: types.FETCH_PUBLISHED_CONTENT_COMPLETED, - data: { - fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), - } - }) - }) + if (isFileInfoListPending === undefined) { + dispatch(doFileList()) + } } } diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js index c3628821d..a570cd413 100644 --- a/ui/js/component/fileActions/index.js +++ b/ui/js/component/fileActions/index.js @@ -19,6 +19,7 @@ import { import { doCloseModal, doOpenModal, + doHistoryBack, } from 'actions/app' import { doFetchAvailability @@ -55,7 +56,10 @@ const perform = (dispatch) => ({ closeModal: () => dispatch(doCloseModal()), openInFolder: (fileInfo) => dispatch(doOpenFileInFolder(fileInfo)), openInShell: (fileInfo) => dispatch(doOpenFileInShell(fileInfo)), - deleteFile: (fileInfo, deleteFromComputer) => dispatch(doDeleteFile(fileInfo, deleteFromComputer)), + deleteFile: (fileInfo, deleteFromComputer) => { + dispatch(doHistoryBack()) + dispatch(doDeleteFile(fileInfo, deleteFromComputer)) + }, openModal: (modal) => dispatch(doOpenModal(modal)), startDownload: (uri) => dispatch(doPurchaseUri(uri)), loadVideo: (uri) => dispatch(doLoadVideo(uri)) diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx index 3f7c7561a..c1e9d6e3c 100644 --- a/ui/js/component/fileActions/view.jsx +++ b/ui/js/component/fileActions/view.jsx @@ -72,7 +72,19 @@ class FileActions extends React.Component { let content - if (!fileInfo && isAvailable === undefined) { + if (downloading) { + + const + progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0, + label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...', + labelWithIcon = {label}; + + content =
+
{labelWithIcon}
+ {labelWithIcon} +
+ + } else if (!fileInfo && isAvailable === undefined) { content = @@ -90,18 +102,6 @@ class FileActions extends React.Component { content = { startDownload(uri) } } />; - } else if (downloading) { - - const - progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0, - label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...', - labelWithIcon = {label}; - - content =
-
{labelWithIcon}
- {labelWithIcon} -
- } else if (fileInfo && fileInfo.download_path) { content = openInShell(fileInfo)} />; } else { @@ -133,7 +133,7 @@ class FileActions extends React.Component { contentLabel="Not enough credits" type="confirm" confirmButtonLabel="Remove" - onConfirmed={() => deleteFile(uri, fileInfo, deleteChecked)} + onConfirmed={() => deleteFile(fileInfo.outpoint, deleteChecked)} onAborted={closeModal}>

Are you sure you'd like to remove {title} from LBRY?

diff --git a/ui/js/component/fileList/view.jsx b/ui/js/component/fileList/view.jsx index 6130a5ffb..eb3b620b8 100644 --- a/ui/js/component/fileList/view.jsx +++ b/ui/js/component/fileList/view.jsx @@ -60,7 +60,6 @@ class FileList extends React.Component { handleSortChanged, fetching, fileInfos, - hidePrices, } = this.props const { sortBy, @@ -72,7 +71,7 @@ class FileList extends React.Component { contentName: fileInfo.name, channelName: fileInfo.channel_name, }) - content.push() + content.push() }) return (
diff --git a/ui/js/component/video/view.jsx b/ui/js/component/video/view.jsx index 3559a728e..3d364bcc9 100644 --- a/ui/js/component/video/view.jsx +++ b/ui/js/component/video/view.jsx @@ -4,14 +4,13 @@ import Link from 'component/link'; import Modal from 'component/modal'; class VideoPlayButton extends React.Component { - confirmPurchaseClick() { + onPurchaseConfirmed() { this.props.closeModal() this.props.startPlaying() this.props.loadVideo(this.props.uri) } onWatchClick() { - console.log(this) this.props.purchaseUri(this.props.uri).then(() => { if (!this.props.modal) { this.props.startPlaying() @@ -59,7 +58,7 @@ class VideoPlayButton extends React.Component { type="confirm" isOpen={modal == 'affirmPurchase'} contentLabel="Confirm Purchase" - onConfirmed={this.confirmPurchaseClick.bind(this)} + onConfirmed={this.onPurchaseConfirmed.bind(this)} onAborted={closeModal}> This will purchase {title} for credits. @@ -107,8 +106,8 @@ class Video extends React.Component { } return ( -
{ - isPlaying || isReadyToPlay ? +
{ + isPlaying || isLoading ? (!isReadyToPlay ? this is the world's worst loading screen and we shipped our software with it anyway...

{loadStatusMessage}
: ) : diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index 2d548bc48..3607583e3 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -38,12 +38,10 @@ export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED' export const RESOLVE_URI_CANCELED = 'RESOLVE_URI_CANCELED' export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED' export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED' +export const CLAIM_LIST_MINE_STARTED = 'CLAIM_LIST_MINE_STARTED' +export const CLAIM_LIST_MINE_COMPLETED = 'CLAIM_LIST_MINE_COMPLETED' export const FILE_LIST_STARTED = 'FILE_LIST_STARTED' export const FILE_LIST_COMPLETED = 'FILE_LIST_COMPLETED' -export const FETCH_DOWNLOADED_CONTENT_STARTED = 'FETCH_DOWNLOADED_CONTENT_STARTED' -export const FETCH_DOWNLOADED_CONTENT_COMPLETED = 'FETCH_DOWNLOADED_CONTENT_COMPLETED' -export const FETCH_PUBLISHED_CONTENT_STARTED = 'FETCH_PUBLISHED_CONTENT_STARTED' -export const FETCH_PUBLISHED_CONTENT_COMPLETED = 'FETCH_PUBLISHED_CONTENT_COMPLETED' export const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED' export const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED' export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED' @@ -57,9 +55,7 @@ export const DOWNLOADING_COMPLETED = 'DOWNLOADING_COMPLETED' export const PLAY_VIDEO_STARTED = 'PLAY_VIDEO_STARTED' export const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED' export const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED' -export const DELETE_FILE_STARTED = 'DELETE_FILE_STARTED' -export const DELETE_FILE_COMPLETED = 'DELETE_FILE_COMPLETED' -export const FETCH_MY_CLAIMS_COMPLETED = 'FETCH_MY_CLAIMS_COMPLETED' +export const FILE_DELETE = 'FILE_DELETE' // Search export const SEARCH_STARTED = 'SEARCH_STARTED' diff --git a/ui/js/lbry.js b/ui/js/lbry.js index ad7e7b6bd..6e9f8e691 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -7,6 +7,25 @@ import {getLocal, getSession, setSession, setLocal} from './utils.js'; const {remote, ipcRenderer} = require('electron'); const menu = remote.require('./menu/main-menu'); +let lbry = { + isConnected: false, + daemonConnectionString: 'http://localhost:5279/lbryapi', + webUiUri: 'http://localhost:5279', + peerListTimeout: 6000, + pendingPublishTimeout: 20 * 60 * 1000, + colors: { + primary: '#155B4A' + }, + defaultClientSettings: { + showNsfw: false, + showUnavailable: true, + debug: false, + useCustomLighthouseServers: false, + customLighthouseServers: [], + showDeveloperMenu: false, + } +}; + /** * Records a publish attempt in local storage. Returns a dictionary with all the data needed to * needed to make a dummy claim or file info object. @@ -40,14 +59,14 @@ function removePendingPublishIfNeeded({name, channel_name, outpoint}) { return pub.outpoint === outpoint || (pub.name === name && (!channel_name || pub.channel_name === channel_name)); } - setLocal('pendingPublishes', getPendingPublishes().filter(pub => !pubMatches(pub))); + setLocal('pendingPublishes', lbry.getPendingPublishes().filter(pub => !pubMatches(pub))); } /** * Gets the current list of pending publish attempts. Filters out any that have timed out and * removes them from the list. */ -function getPendingPublishes() { +lbry.getPendingPublishes = function() { const pendingPublishes = getLocal('pendingPublishes') || []; const newPendingPublishes = pendingPublishes.filter(pub => Date.now() - pub.time <= lbry.pendingPublishTimeout); setLocal('pendingPublishes', newPendingPublishes); @@ -59,7 +78,7 @@ function getPendingPublishes() { * provided along withe the name. If no pending publish is found, returns null. */ function getPendingPublish({name, channel_name, outpoint}) { - const pendingPublishes = getPendingPublishes(); + const pendingPublishes = lbry.getPendingPublishes(); return pendingPublishes.find( pub => pub.outpoint === outpoint || (pub.name === name && (!channel_name || pub.channel_name === channel_name)) ) || null; @@ -74,26 +93,6 @@ function pendingPublishToDummyFileInfo({name, outpoint, claim_id}) { } window.pptdfi = pendingPublishToDummyFileInfo; -let lbry = { - isConnected: false, - rootPath: '.', - daemonConnectionString: 'http://localhost:5279/lbryapi', - webUiUri: 'http://localhost:5279', - peerListTimeout: 6000, - pendingPublishTimeout: 20 * 60 * 1000, - colors: { - primary: '#155B4A' - }, - defaultClientSettings: { - showNsfw: false, - showUnavailable: true, - debug: false, - useCustomLighthouseServers: false, - customLighthouseServers: [], - showDeveloperMenu: false, - } -}; - lbry.call = function (method, params, callback, errorCallback, connectFailedCallback) { return jsonrpc.call(lbry.daemonConnectionString, method, params, callback, errorCallback, connectFailedCallback); } @@ -159,12 +158,6 @@ lbry.sendToAddress = function(amount, address, callback, errorCallback) { lbry.call("send_amount_to_address", { "amount" : amount, "address": address }, callback, errorCallback); } -lbry.getMyClaim = function(name, callback) { - lbry.call('claim_list_mine', {}, (claims) => { - callback(claims.find((claim) => claim.name == name) || null); - }); -} - /** * Takes a LBRY URI; will first try and calculate a total cost using * Lighthouse. If Lighthouse can't be reached, it just retrives the @@ -218,40 +211,6 @@ lbry.getCostInfo = function(uri) { return lbry.costPromiseCache[uri]; } -lbry.getMyClaims = function(callback) { - lbry.call('get_name_claims', {}, callback); -} - -lbry.removeFile = function(outpoint, deleteTargetFile=true, callback) { - this._removedFiles.push(outpoint); - // this._updateFileInfoSubscribers(outpoint); - - lbry.file_delete({ - outpoint: outpoint, - delete_target_file: deleteTargetFile, - }).then(callback); -} - -lbry.getFileInfoWhenListed = function(name, callback, timeoutCallback, tryNum=0) { - function scheduleNextCheckOrTimeout() { - if (timeoutCallback && tryNum > 200) { - timeoutCallback(); - } else { - setTimeout(() => lbry.getFileInfoWhenListed(name, callback, timeoutCallback, tryNum + 1), 250); - } - } - - // Calls callback with file info when it appears in the lbrynet file manager. - // If timeoutCallback is provided, it will be called if the file fails to appear. - lbry.file_list({name: name}).then(([fileInfo]) => { - if (fileInfo) { - callback(fileInfo); - } else { - scheduleNextCheckOrTimeout(); - } - }, () => scheduleNextCheckOrTimeout()); -} - /** * Publishes a file. The optional fileListedCallback is called when the file becomes available in * lbry.file_list() during the publish process. @@ -292,10 +251,6 @@ lbry.publish = function(params, fileListedCallback, publishedCallback, errorCall fileListedCallback(true); } }, 2000); - - //lbry.getFileInfoWhenListed(params.name, function(fileInfo) { - // fileListedCallback(fileInfo); - //}); } @@ -350,29 +305,10 @@ lbry.formatName = function(name) { return name; } -lbry.nameIsValid = function(name, checkCase=true) { - const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); - return regexp.test(name); -} - -lbry.loadJs = function(src, type, onload) -{ - var lbryScriptTag = document.getElementById('lbry'), - newScriptTag = document.createElement('script'), - type = type || 'text/javascript'; - - newScriptTag.src = src; - newScriptTag.type = type; - if (onload) - { - newScriptTag.onload = onload; - } - lbryScriptTag.parentNode.insertBefore(newScriptTag, lbryScriptTag); -} lbry.imagePath = function(file) { - return lbry.rootPath + '/img/' + file; + return 'img/' + file; } lbry.getMediaType = function(contentType, fileName) { @@ -406,17 +342,6 @@ lbry.stop = function(callback) { lbry._subscribeIdCount = 0; lbry._balanceSubscribeCallbacks = {}; lbry._balanceSubscribeInterval = 5000; -lbry._removedFiles = []; -lbry._claimIdOwnershipCache = {}; - -lbry._updateClaimOwnershipCache = function(claimId) { - lbry.getMyClaims((claimInfos) => { - lbry._claimIdOwnershipCache[claimId] = !!claimInfos.reduce(function(match, claimInfo) { - return match || claimInfo.claim_id == claimId; - }, false); - }); - -}; lbry._balanceUpdateInterval = null; lbry._updateBalanceSubscribers = function() { @@ -493,7 +418,7 @@ lbry.file_list = function(params={}) { lbry.call('file_list', params, (fileInfos) => { removePendingPublishIfNeeded({name, channel_name, outpoint}); - const dummyFileInfos = getPendingPublishes().map(pendingPublishToDummyFileInfo); + const dummyFileInfos = lbry.getPendingPublishes().map(pendingPublishToDummyFileInfo); resolve([...fileInfos, ...dummyFileInfos]); }, reject, reject); }); @@ -506,7 +431,7 @@ lbry.claim_list_mine = function(params={}) { removePendingPublishIfNeeded({name, channel_name, outpoint: txid + ':' + nout}); } - const dummyClaims = getPendingPublishes().map(pendingPublishToDummyClaim); + const dummyClaims = lbry.getPendingPublishes().map(pendingPublishToDummyClaim); resolve([...claims, ...dummyClaims]); }, reject, reject) }); diff --git a/ui/js/lbryuri.js b/ui/js/lbryuri.js index 637a2fd67..680c42d65 100644 --- a/ui/js/lbryuri.js +++ b/ui/js/lbryuri.js @@ -175,6 +175,11 @@ lbryuri.isValid = function(uri) { return parts && parts.name; } +lbryuri.isValidName = function(name, checkCase=true) { + const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); + return regexp.test(name); +} + lbryuri.isClaimable = function(uri) { let parts try { diff --git a/ui/js/main.js b/ui/js/main.js index a52e4b943..f9579804b 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -34,13 +34,15 @@ window.addEventListener('contextmenu', (event) => { event.preventDefault(); }); -window.addEventListener('popstate', (event) => { +window.addEventListener('popstate', (event, param) => { const queryString = document.location.search const pathParts = document.location.pathname.split('/') const route = '/' + pathParts[pathParts.length - 1] if (route.match(/html$/)) return + console.log('title should be set here, but it is not in popstate? TODO') + app.store.dispatch(doChangePath(`${route}${queryString}`)) }) diff --git a/ui/js/page/channel/index.js b/ui/js/page/channel/index.js index 3091761df..4ff8d8206 100644 --- a/ui/js/page/channel/index.js +++ b/ui/js/page/channel/index.js @@ -6,18 +6,28 @@ import { doFetchClaimsByChannel } from 'actions/content' import { - makeSelectClaimsForChannel + makeSelectClaimForUri, + makeSelectClaimsInChannelForUri } from 'selectors/claims' import ChannelPage from './view' -// -// const select = (state) => ({ -// uri: selectCurrentUri(state), -// claim: selectCurrentUriClaim(state), -// claims: selectCurrentUriClaims(state) -// }) + +import FilePage from './view' + +const makeSelect = () => { + const selectClaim = makeSelectClaimForUri(), + selectClaimsInChannel = makeSelectClaimsInChannelForUri() + + const select = (state, props) => ({ + claim: selectClaim(state, props), + claimsInChannel: selectClaimsInChannel(state, props) + }) + + return select +} const perform = (dispatch) => ({ + // fetchClaims: () => { console.log('fetch claims') } fetchClaims: (uri) => dispatch(doFetchClaimsByChannel(uri)) }) -export default connect(null, perform)(ChannelPage) +export default connect(makeSelect, perform)(ChannelPage) diff --git a/ui/js/page/channel/view.jsx b/ui/js/page/channel/view.jsx index 1542f14af..3caa59594 100644 --- a/ui/js/page/channel/view.jsx +++ b/ui/js/page/channel/view.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import lbryuri from 'lbryuri' class ChannelPage extends React.Component{ componentDidMount() { @@ -10,19 +11,19 @@ class ChannelPage extends React.Component{ } fetchClaims(props) { - if (props.claims === undefined) { + if (props.claimsInChannel === undefined) { props.fetchClaims(props.uri) } } render() { const { - claims, + claimsInChannel, claim, uri } = this.props - console.log(claims); + console.log(claimsInChannel); return
@@ -36,7 +37,9 @@ class ChannelPage extends React.Component{
- {claims} + {claimsInChannel ? + claimsInChannel.map((claim) => ) + : ''}
diff --git a/ui/js/page/fileListDownloaded/index.js b/ui/js/page/fileListDownloaded/index.js index 7122ff5fd..101933bd1 100644 --- a/ui/js/page/fileListDownloaded/index.js +++ b/ui/js/page/fileListDownloaded/index.js @@ -3,11 +3,11 @@ import { connect } from 'react-redux' import { - doFetchDownloadedContent, + doFetchFileInfosAndPublishedClaims, } from 'actions/file_info' import { - selectDownloadedFileInfo, - selectFetchingDownloadedContent, + selectFileInfosDownloaded, + selectFileListDownloadedOrPublishedIsPending, } from 'selectors/file_info' import { doNavigate, @@ -15,13 +15,13 @@ import { import FileListDownloaded from './view' const select = (state) => ({ - downloadedContent: selectDownloadedFileInfo(state), - fetching: selectFetchingDownloadedContent(state), + fileInfos: selectFileInfosDownloaded(state), + isPending: selectFileListDownloadedOrPublishedIsPending(state), }) const perform = (dispatch) => ({ navigate: (path) => dispatch(doNavigate(path)), - fetchFileListDownloaded: () => dispatch(doFetchDownloadedContent()), + fetchFileInfosDownloaded: () => dispatch(doFetchFileInfosAndPublishedClaims()), }) export default connect(select, perform)(FileListDownloaded) diff --git a/ui/js/page/fileListDownloaded/view.jsx b/ui/js/page/fileListDownloaded/view.jsx index 2c041a267..670b27191 100644 --- a/ui/js/page/fileListDownloaded/view.jsx +++ b/ui/js/page/fileListDownloaded/view.jsx @@ -12,21 +12,21 @@ import SubHeader from 'component/subHeader' class FileListDownloaded extends React.Component { componentWillMount() { - this.props.fetchFileListDownloaded() + this.props.fetchFileInfosDownloaded() } render() { const { - downloadedContent, - fetching, + fileInfos, + isPending, navigate, } = this.props let content - if (downloadedContent && downloadedContent.length > 0) { - content = + if (fileInfos && fileInfos.length > 0) { + content = } else { - if (fetching) { + if (isPending) { content = } else { content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! diff --git a/ui/js/page/fileListPublished/index.js b/ui/js/page/fileListPublished/index.js index 22f2b8736..fbf0bcb71 100644 --- a/ui/js/page/fileListPublished/index.js +++ b/ui/js/page/fileListPublished/index.js @@ -3,13 +3,11 @@ import { connect } from 'react-redux' import { - doFetchPublishedContent, -} from 'actions/content' + doFetchFileInfosAndPublishedClaims, +} from 'actions/file_info' import { - selectFetchingPublishedContent, -} from 'selectors/content' -import { - selectPublishedFileInfo, + selectFileInfosPublished, + selectFileListDownloadedOrPublishedIsPending } from 'selectors/file_info' import { doNavigate, @@ -17,13 +15,13 @@ import { import FileListPublished from './view' const select = (state) => ({ - publishedContent: selectPublishedFileInfo(state), - fetching: selectFetchingPublishedContent(state), + fileInfos: selectFileInfosPublished(state), + isPending: selectFileListDownloadedOrPublishedIsPending(state), }) const perform = (dispatch) => ({ navigate: (path) => dispatch(doNavigate(path)), - fetchFileListPublished: () => dispatch(doFetchPublishedContent()), + fetchFileListPublished: () => dispatch(doFetchFileInfosAndPublishedClaims()), }) export default connect(select, perform)(FileListPublished) diff --git a/ui/js/page/fileListPublished/view.jsx b/ui/js/page/fileListPublished/view.jsx index 365aa061c..488a45086 100644 --- a/ui/js/page/fileListPublished/view.jsx +++ b/ui/js/page/fileListPublished/view.jsx @@ -3,7 +3,7 @@ import lbry from 'lbry.js'; import lbryuri from 'lbryuri.js'; import Link from 'component/link'; import {FormField} from 'component/form.js'; -import {FileTile} from 'component/fileTile'; +import FileTile from 'component/fileTile'; import rewards from 'rewards.js'; import lbryio from 'lbryio.js'; import {BusyMessage, Thumbnail} from 'component/common.js'; @@ -16,7 +16,7 @@ class FileListPublished extends React.Component { } componentDidUpdate() { - if(this.props.publishedContent.length > 0) this._requestPublishReward() + if(this.props.fileInfos.length > 0) this._requestPublishReward() } _requestPublishReward() { @@ -38,17 +38,17 @@ class FileListPublished extends React.Component { render() { const { - publishedContent, - fetching, + fileInfos, + isPending, navigate, } = this.props let content - if (publishedContent && publishedContent.length > 0) { - content = + if (fileInfos && fileInfos.length > 0) { + content = } else { - if (fetching) { + if (isPending) { content = } else { content = You haven't downloaded anything from LBRY yet. Go navigate('/discover')} label="search for your first download" />! diff --git a/ui/js/page/filePage/view.jsx b/ui/js/page/filePage/view.jsx index 20b87a83f..72d95a276 100644 --- a/ui/js/page/filePage/view.jsx +++ b/ui/js/page/filePage/view.jsx @@ -61,10 +61,10 @@ class FilePage extends React.Component{ render() { const { claim, + fileInfo, metadata, contentType, uri, - fileInfo, } = this.props if (!claim || !metadata) { diff --git a/ui/js/page/help/view.jsx b/ui/js/page/help/view.jsx index c57c4d1f0..2d4f516a6 100644 --- a/ui/js/page/help/view.jsx +++ b/ui/js/page/help/view.jsx @@ -24,9 +24,6 @@ var HelpPage = React.createClass({ }); }); }, - componentDidMount: function() { - document.title = "Help"; - }, render: function() { let ver, osName, platform, newVerLink; if (this.state.versionInfo) { diff --git a/ui/js/page/publish/index.js b/ui/js/page/publish/index.js index 29347b6ed..d083fd118 100644 --- a/ui/js/page/publish/index.js +++ b/ui/js/page/publish/index.js @@ -5,9 +5,13 @@ import { import { doNavigate, } from 'actions/app' +import { + selectMyClaims +} from 'selectors/claims' import PublishPage from './view' const select = (state) => ({ + myClaims: selectMyClaims(state) }) const perform = (dispatch) => ({ diff --git a/ui/js/page/publish/view.jsx b/ui/js/page/publish/view.jsx index cb0b152b6..73c0df9e6 100644 --- a/ui/js/page/publish/view.jsx +++ b/ui/js/page/publish/view.jsx @@ -1,5 +1,6 @@ import React from 'react'; import lbry from 'lbry'; +import lbryuri from 'lbryuri' import {FormField, FormRow} from 'component/form.js'; import Link from 'component/link'; import rewards from 'rewards'; @@ -169,7 +170,7 @@ var PublishPage = React.createClass({ return; } - if (!lbry.nameIsValid(rawName, false)) { + if (!lbryuri.isValidName(rawName, false)) { this.refs.name.showError('LBRY names must contain only letters, numbers and dashes.'); return; } @@ -182,50 +183,45 @@ var PublishPage = React.createClass({ myClaimExists: null, }); - lbry.getMyClaim(name, (myClaimInfo) => { + const myClaimInfo = Object.values(this.props.myClaims).find(claim => claim.name === name) + + this.setState({ + myClaimExists: !!myClaimInfo, + }); + lbry.resolve({uri: name}).then((claimInfo) => { if (name != this.state.name) { - // A new name has been typed already, so bail return; } - this.setState({ - myClaimExists: !!myClaimInfo, - }); - lbry.resolve({uri: name}).then((claimInfo) => { - if (name != this.state.name) { - return; - } - - if (!claimInfo) { - this.setState({ - nameResolved: false, - }); - } else { - const topClaimIsMine = (myClaimInfo && myClaimInfo.claim.amount >= claimInfo.claim.amount); - const newState = { - nameResolved: true, - topClaimValue: parseFloat(claimInfo.claim.amount), - myClaimExists: !!myClaimInfo, - myClaimValue: myClaimInfo ? parseFloat(myClaimInfo.claim.amount) : null, - myClaimMetadata: myClaimInfo ? myClaimInfo.value : null, - topClaimIsMine: topClaimIsMine, - }; - - if (topClaimIsMine) { - newState.bid = myClaimInfo.claim.amount; - } else if (this.state.myClaimMetadata) { - // Just changed away from a name we have a claim on, so clear pre-fill - newState.bid = ''; - } - - this.setState(newState); - } - }, () => { // Assume an error means the name is available + if (!claimInfo) { this.setState({ - name: name, nameResolved: false, - myClaimExists: false, }); + } else { + const topClaimIsMine = (myClaimInfo && myClaimInfo.claim.amount >= claimInfo.claim.amount); + const newState = { + nameResolved: true, + topClaimValue: parseFloat(claimInfo.claim.amount), + myClaimExists: !!myClaimInfo, + myClaimValue: myClaimInfo ? parseFloat(myClaimInfo.claim.amount) : null, + myClaimMetadata: myClaimInfo ? myClaimInfo.value : null, + topClaimIsMine: topClaimIsMine, + }; + + if (topClaimIsMine) { + newState.bid = myClaimInfo.claim.amount; + } else if (this.state.myClaimMetadata) { + // Just changed away from a name we have a claim on, so clear pre-fill + newState.bid = ''; + } + + this.setState(newState); + } + }, () => { // Assume an error means the name is available + this.setState({ + name: name, + nameResolved: false, + myClaimExists: false, }); }); }, @@ -287,7 +283,7 @@ var PublishPage = React.createClass({ handleNewChannelNameChange: function (event) { const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value); - if (newChannelName.length > 1 && !lbry.nameIsValid(newChannelName.substr(1), false)) { + if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) { this.refs.newChannelName.showError('LBRY channel names must contain only letters, numbers and dashes.'); return; } else { diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx index 0d0b0da5e..96983139c 100644 --- a/ui/js/page/showPage/view.jsx +++ b/ui/js/page/showPage/view.jsx @@ -1,7 +1,9 @@ import React from 'react'; +import lbryuri from 'lbryuri' import { BusyMessage, } from 'component/common'; +import ChannelPage from 'page/channel' import FilePage from 'page/filePage' class ShowPage extends React.Component{ @@ -21,8 +23,6 @@ class ShowPage extends React.Component{ uri, } = props - console.log('show page resolve ' + uri) - console.log('isResolving: ' + isResolvingUri) if(!isResolvingUri && claim === undefined && uri) { resolveUri(uri) } @@ -49,8 +49,7 @@ class ShowPage extends React.Component{
} else if (claim.name.length && claim.name[0] === '@') { - innerContent = "channel" - // innerContent = + innerContent = } else if (claim) { innerContent = diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index b8885d98a..6acf0f111 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -39,6 +39,24 @@ reducers[types.RESOLVE_URI_CANCELED] = function(state, action) { }) } + +reducers[types.CLAIM_LIST_MINE_STARTED] = function(state, action) { + return Object.assign({}, state, { + isClaimListMinePending: true + }) +} + +reducers[types.CLAIM_LIST_MINE_COMPLETED] = function(state, action) { + const myClaims = Object.assign({}, state.myClaims) + action.data.claims.forEach((claim) => { + myClaims[claim.claim_id] = claim + }) + return Object.assign({}, state, { + isClaimListMinePending: false, + myClaims: myClaims + }) +} + reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) { const { uri, @@ -56,23 +74,6 @@ reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) { }) } -reducers[types.FETCH_MY_CLAIMS_COMPLETED] = function(state, action) { - const { - claims, - } = action.data - const newMine = Object.assign({}, state.mine) - const newById = Object.assign({}, newMine.byId) - - claims.forEach(claim => { - newById[claim.claim_id] = claim - }) - newMine.byId = newById - - return Object.assign({}, state, { - mine: newMine, - }) -} - export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/reducers/file_info.js b/ui/js/reducers/file_info.js index affd4103d..811c829ef 100644 --- a/ui/js/reducers/file_info.js +++ b/ui/js/reducers/file_info.js @@ -64,22 +64,19 @@ reducers[types.DOWNLOADING_STARTED] = function(state, action) { outpoint, fileInfo, } = action.data - const newFileInfos = Object.assign({}, state.fileInfos) - const newDownloading = Object.assign({}, state.downloading) - const newDownloadingByUri = Object.assign({}, newDownloading.byUri) - const newLoading = Object.assign({}, state.loading) - const newLoadingByUri = Object.assign({}, newLoading) - newDownloadingByUri[uri] = true - newDownloading.byUri = newDownloadingByUri + const newFileInfos = Object.assign({}, state.fileInfos) + const newDownloading = Object.assign({}, state.urisDownloading) + const newLoading = Object.assign({}, state.urisLoading) + + newDownloading[uri] = true newFileInfos[outpoint] = fileInfo - delete newLoadingByUri[uri] - newLoading.byUri = newLoadingByUri + delete newLoading[uri] return Object.assign({}, state, { - downloading: newDownloading, + urisDownloading: newDownloading, + urisLoading: newLoading, fileInfos: newFileInfos, - loading: newLoading, }) } @@ -89,15 +86,16 @@ reducers[types.DOWNLOADING_PROGRESSED] = function(state, action) { outpoint, fileInfo, } = action.data + const newFileInfos = Object.assign({}, state.fileInfos) - const newDownloading = Object.assign({}, state.downloading) + const newDownloading = Object.assign({}, state.urisDownloading) newFileInfos[outpoint] = fileInfo newDownloading[uri] = true return Object.assign({}, state, { - fileInfos: newByUri, - downloading: newDownloading + fileInfos: newFileInfos, + urisDownloading: newDownloading }) } @@ -107,49 +105,29 @@ reducers[types.DOWNLOADING_COMPLETED] = function(state, action) { outpoint, fileInfo, } = action.data + const newFileInfos = Object.assign({}, state.fileInfos) - const newDownloading = Object.assign({}, state.downloading) - const newDownloadingByUri = Object.assign({}, newDownloading.byUri) + const newDownloading = Object.assign({}, state.urisDownloading) newFileInfos[outpoint] = fileInfo - delete newDownloadingByUri[uri] - newDownloading.byUri = newDownloadingByUri + delete newDownloading[uri] return Object.assign({}, state, { fileInfos: newFileInfos, - downloading: newDownloading, + urisDownloading: newDownloading, }) } -reducers[types.DELETE_FILE_STARTED] = function(state, action) { +reducers[types.FILE_DELETE] = function(state, action) { const { - outpoint + outpoint, } = action.data - const newDeleting = Object.assign({}, state.deleting) - const newByUri = Object.assign({}, newDeleting.byUri) - newFileInfos[outpoint] = true - newDeleting.byUri = newFileInfos - - return Object.assign({}, state, { - deleting: newDeleting, - }) -} - -reducers[types.DELETE_FILE_COMPLETED] = function(state, action) { - const { - uri, - } = action.data - const newDeleting = Object.assign({}, state.deleting) - const newDeletingByUri = Object.assign({}, newDeleting.byUri) const newFileInfos = Object.assign({}, state.fileInfos) - delete newDeletingByUri[uri] - newDeleting.byUri = newDeletingByUri delete newFileInfos[outpoint] return Object.assign({}, state, { - deleting: newDeleting, fileInfos: newFileInfos, }) } @@ -158,14 +136,13 @@ reducers[types.LOADING_VIDEO_STARTED] = function(state, action) { const { uri, } = action.data - const newLoading = Object.assign({}, state.loading) - const newFileInfos = Object.assign({}, newLoading.byUri) - newFileInfos[outpoint] = true - newLoading.byUri = newFileInfos + const newLoading = Object.assign({}, state.urisLoading) + + newLoading[uri] = true return Object.assign({}, state, { - loading: newLoading, + urisLoading: newLoading, }) } @@ -173,59 +150,16 @@ reducers[types.LOADING_VIDEO_FAILED] = function(state, action) { const { uri, } = action.data - const newLoading = Object.assign({}, state.loading) - const newFileInfos = Object.assign({}, newLoading.byUri) - delete newFileInfos[outpoint] - newLoading.byUri = newFileInfos + const newLoading = Object.assign({}, state.urisLoading) + + delete newLoading[uri] return Object.assign({}, state, { - loading: newLoading, + urisLoading: newLoading, }) } -reducers[types.FETCH_DOWNLOADED_CONTENT_STARTED] = function(state, action) { - return Object.assign({}, state, { - fetchingDownloadedContent: true, - }) -} - -reducers[types.FETCH_DOWNLOADED_CONTENT_COMPLETED] = function(state, action) { - const newFileInfos = Object.assign({}, state.fileInfos) - - action.data.fileInfos.forEach(fileInfo => { - newFileInfos[fileInfo.outpoint] = fileInfo - }) - - return Object.assign({}, state, { - fileInfos: newFileInfos, - fetchingDownloadedContent: false - }) -} - -reducers[types.FETCH_PUBLISHED_CONTENT_STARTED] = function(state, action) { - return Object.assign({}, state, { - fetchingPublishedContent: true, - }) -} - -reducers[types.FETCH_PUBLISHED_CONTENT_COMPLETED] = function(state, action) { - const { - fileInfos - } = action.data - const newFileInfos = Object.assign({}, state.fileInfos) - - fileInfos.forEach(fileInfo => { - newFileInfos[fileInfo.outpoint] = fileInfo - }) - - return Object.assign({}, state, { - fileInfos: newFileInfos, - fetchingPublishedContent: false - }) -} - - export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index 9b7612859..9a76b872e 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -15,17 +15,6 @@ export const selectAllClaimsByChannel = createSelector( (state) => state.claimsByChannel || {} ) -export const selectClaimsForChannel = (state, props) => { - return selectAllClaimsByChannel(state)[props.uri] -} - -export const makeSelectClaimsForChannel = () => { - return createSelector( - selectClaimsForChannel, - (claim) => claim - ) -} - const selectClaimForUri = (state, props) => { const uri = lbryuri.normalize(props.uri) return selectClaimsByUri(state)[uri] @@ -38,6 +27,17 @@ export const makeSelectClaimForUri = () => { ) } +export const selectClaimsInChannelForUri = (state, props) => { + return selectAllClaimsByChannel(state)[props.uri] +} + +export const makeSelectClaimsInChannelForUri = () => { + return createSelector( + selectClaimsInChannelForUri, + (claims) => claims + ) +} + const selectMetadataForUri = (state, props) => { const claim = selectClaimForUri(state, props) const metadata = claim && claim.value && claim.value.stream && claim.value.stream.metadata @@ -73,26 +73,25 @@ export const makeSelectContentTypeForUri = () => { ) } -export const selectMyClaims = createSelector( +export const selectClaimListMineIsPending = createSelector( _selectState, - (state) => state.mine || {} + (state) => state.isClaimListMinePending ) -export const selectMyClaimsById = createSelector( - selectMyClaims, - (mine) => mine.byId || {} +export const selectMyClaims = createSelector( + _selectState, + (state) => state.myClaims || {} ) export const selectMyClaimsOutpoints = createSelector( - selectMyClaimsById, - (byId) => { - const outpoints = [] - Object.keys(byId).forEach(key => { - const claim = byId[key] - const outpoint = `${claim.txid}:${claim.nout}` - outpoints.push(outpoint) - }) + selectMyClaims, + (claims) => { + if (!claims) { + return [] + } - return outpoints + return Object.values(claims).map((claim) => { + return `${claim.txid}:${claim.nout}` + }) } ) diff --git a/ui/js/selectors/file_info.js b/ui/js/selectors/file_info.js index c9104bbc2..cf7895d56 100644 --- a/ui/js/selectors/file_info.js +++ b/ui/js/selectors/file_info.js @@ -1,69 +1,38 @@ +import lbry from 'lbry' import { createSelector, } from 'reselect' import { selectClaimsByUri, + selectClaimListMineIsPending, selectMyClaimsOutpoints, } from 'selectors/claims' export const _selectState = state => state.fileInfo || {} -export const selectIsFileListPending = createSelector( - _selectState, - (state) => state.isFileListPending -) - export const selectAllFileInfos = createSelector( _selectState, (state) => state.fileInfos || {} ) -export const selectDownloading = createSelector( +export const selectFileListIsPending = createSelector( _selectState, - (state) => state.downloading || {} + (state) => state.isFileListPending ) -export const selectDownloadingByUri = createSelector( - selectDownloading, - (downloading) => downloading.byUri || {} -) - -export const selectFetchingDownloadedContent = createSelector( - _selectState, - (state) => !!state.fetchingDownloadedContent -) - -export const selectDownloadedContent = createSelector( - _selectState, - (state) => state.downloadedContent || {} -) - -export const selectDownloadedContentFileInfos = createSelector( - selectDownloadedContent, - (downloadedContent) => downloadedContent.fileInfos || [] -) - -export const selectFetchingPublishedContent = createSelector( - _selectState, - (state) => !!state.fetchingPublishedContent -) - -export const selectPublishedContent = createSelector( - _selectState, - (state) => state.publishedContent || {} +export const selectFileListDownloadedOrPublishedIsPending = createSelector( + selectFileListIsPending, + selectClaimListMineIsPending, + (isFileListPending, isClaimListMinePending) => isFileListPending || isClaimListMinePending ) export const selectFileInfoForUri = (state, props) => { const claims = selectClaimsByUri(state), claim = claims[props.uri], + fileInfos = selectAllFileInfos(state), outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined - console.log('select file info') - console.log(claims) - console.log(claim) - console.log(outpoint) - console.log(selectAllFileInfos(state)) - return outpoint ? selectAllFileInfos(state)[outpoint] : undefined + return outpoint && fileInfos ? fileInfos[outpoint] : undefined } export const makeSelectFileInfoForUri = () => { @@ -73,8 +42,13 @@ export const makeSelectFileInfoForUri = () => { ) } +export const selectUrisDownloading = createSelector( + _selectState, + (state) => state.urisDownloading || {} +) + const selectDownloadingForUri = (state, props) => { - const byUri = selectDownloadingByUri(state) + const byUri = selectUrisDownloading(state) return byUri[props.uri] } @@ -85,18 +59,13 @@ export const makeSelectDownloadingForUri = () => { ) } -export const selectLoading = createSelector( +export const selectUrisLoading = createSelector( _selectState, - (state) => state.loading || {} -) - -export const selectLoadingByUri = createSelector( - selectLoading, - (loading) => loading.byUri || {} + (state) => state.urisLoading || {} ) const selectLoadingForUri = (state, props) => { - const byUri = selectLoadingByUri(state) + const byUri = selectUrisLoading(state) return byUri[props.uri] } @@ -107,13 +76,13 @@ export const makeSelectLoadingForUri = () => { ) } -export const selectDownloadedFileInfo = createSelector( +export const selectFileInfosDownloaded = createSelector( selectAllFileInfos, - (fileInfos) => { + selectMyClaimsOutpoints, + (fileInfos, myClaimOutpoints) => { const fileInfoList = [] - Object.keys(fileInfos).forEach(outpoint => { - const fileInfo = fileInfos[outpoint] - if (fileInfo.completed || fileInfo.written_bytes) { + Object.values(fileInfos).forEach(fileInfo => { + if (fileInfo && myClaimOutpoints.indexOf(fileInfo.outpoint) === -1 && (fileInfo.completed || fileInfo.written_bytes)) { fileInfoList.push(fileInfo) } }) @@ -121,20 +90,24 @@ export const selectDownloadedFileInfo = createSelector( } ) -export const selectPublishedFileInfo = createSelector( - selectAllFileInfos, - selectMyClaimsOutpoints, - (byUri, outpoints) => { - const fileInfos = [] - outpoints.forEach(outpoint => { - Object.keys(byUri).forEach(key => { - const fileInfo = byUri[key] - if (fileInfo.outpoint == outpoint) { - fileInfos.push(fileInfo) - } - }) - }) - - return fileInfos +export const selectFileInfosPendingPublish = createSelector( + _selectState, + (state) => { + return lbry.getPendingPublishes() + } +) + +export const selectFileInfosPublished = createSelector( + selectAllFileInfos, + selectFileInfosPendingPublish, + selectMyClaimsOutpoints, + (allFileInfos, pendingFileInfos, outpoints) => { + const fileInfos = [] + outpoints.forEach(outpoint => { + if (allFileInfos[outpoint]) { + fileInfos.push(allFileInfos[outpoint]) + } + }) + return [...fileInfos, ...pendingFileInfos] } ) From 3a0506c18b8d0d84f19c7d02ef26f076acd84279 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Thu, 18 May 2017 19:15:54 -0400 Subject: [PATCH 18/18] renable discover list --- ui/js/actions/content.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index a3436fbbb..40ff1b048 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -66,7 +66,6 @@ export function doCancelResolveUri(uri) { export function doFetchFeaturedUris() { return function(dispatch, getState) { - return const state = getState() dispatch({