diff --git a/ui/js/actions/availability.js b/ui/js/actions/availability.js
index d5d14fa19..74c85eaa3 100644
--- a/ui/js/actions/availability.js
+++ b/ui/js/actions/availability.js
@@ -1,5 +1,8 @@
import * as types from 'constants/action_types'
import lbry from 'lbry'
+import {
+ selectCurrentUri,
+} from 'selectors/app'
export function doFetchUriAvailability(uri) {
return function(dispatch, getState) {
@@ -8,14 +11,29 @@ export function doFetchUriAvailability(uri) {
data: { uri }
})
- lbry.get_availability({ uri }, (availability) => {
+ const successCallback = (availability) => {
dispatch({
- type: types.FETCH_AVAILABILITY_COMPLETED',
+ type: types.FETCH_AVAILABILITY_COMPLETED,
data: {
availability,
uri,
}
})
}
+
+ const errorCallback = () => {
+ console.debug('error')
+ }
+
+ lbry.get_availability({ uri }, successCallback, errorCallback)
+ }
+}
+
+export function doFetchCurrentUriAvailability() {
+ return function(dispatch, getState) {
+ const state = getState()
+ const uri = selectCurrentUri(state)
+
+ dispatch(doFetchUriAvailability(uri))
}
}
diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js
index 76f7d5af8..9e9f90e3d 100644
--- a/ui/js/actions/content.js
+++ b/ui/js/actions/content.js
@@ -23,6 +23,9 @@ import {
import {
doOpenModal,
} from 'actions/app'
+import {
+ doFetchCostInfoForUri,
+} from 'actions/cost_info'
import batchActions from 'util/batchActions'
export function doResolveUri(uri) {
@@ -46,6 +49,8 @@ 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 2d513e578..278f1d7b4 100644
--- a/ui/js/actions/cost_info.js
+++ b/ui/js/actions/cost_info.js
@@ -4,11 +4,8 @@ import {
} from 'selectors/app'
import lbry from 'lbry'
-export function doFetchCurrentUriCostInfo() {
+export function doFetchCostInfoForUri(uri) {
return function(dispatch, getState) {
- const state = getState()
- const uri = selectCurrentUri(state)
-
dispatch({
type: types.FETCH_COST_INFO_STARTED,
data: {
@@ -28,3 +25,12 @@ export function doFetchCurrentUriCostInfo() {
}
}
+export function doFetchCurrentUriCostInfo() {
+ return function(dispatch, getState) {
+ const state = getState()
+ const uri = selectCurrentUri(state)
+
+ dispatch(doFetchCostInfoForUri(uri))
+ }
+}
+
diff --git a/ui/js/actions/file_info.js b/ui/js/actions/file_info.js
index 9005e6f01..77763352b 100644
--- a/ui/js/actions/file_info.js
+++ b/ui/js/actions/file_info.js
@@ -6,6 +6,13 @@ import {
import {
selectCurrentUriClaimOutpoint,
} from 'selectors/claims'
+import {
+ doCloseModal,
+} from 'actions/app'
+
+const {
+ shell,
+} = require('electron')
export function doFetchCurrentUriFileInfo() {
return function(dispatch, getState) {
@@ -32,3 +39,40 @@ export function doFetchCurrentUriFileInfo() {
})
}
}
+
+export function doOpenFileInShell(fileInfo) {
+ return function(dispatch, getState) {
+ shell.openItem(fileInfo.download_path)
+ }
+}
+
+export function doOpenFileInFolder(fileInfo) {
+ return function(dispatch, getState) {
+ shell.showItemInFolder(fileInfo.download_path)
+ }
+}
+
+export function doDeleteFile(uri, fileInfo, deleteFromComputer) {
+ return function(dispatch, getState) {
+ dispatch({
+ type: types.DELETE_FILE_STARTED,
+ data: {
+ uri,
+ fileInfo,
+ deleteFromComputer,
+ }
+ })
+
+ const successCallback = () => {
+ dispatch({
+ type: types.DELETE_FILE_COMPLETED,
+ data: {
+ uri,
+ }
+ })
+ dispatch(doCloseModal())
+ }
+
+ lbry.removeFile(fileInfo.outpoint, deleteFromComputer, successCallback)
+ }
+}
diff --git a/ui/js/component/common.js b/ui/js/component/common.js
index 8da20ca8e..aac91004a 100644
--- a/ui/js/component/common.js
+++ b/ui/js/component/common.js
@@ -82,54 +82,6 @@ export let CreditAmount = React.createClass({
}
});
-export let FilePrice = React.createClass({
- _isMounted: false,
-
- propTypes: {
- uri: React.PropTypes.string.isRequired,
- look: React.PropTypes.oneOf(['indicator', 'plain']),
- },
-
- getDefaultProps: function() {
- return {
- look: 'indicator',
- }
- },
-
- componentWillMount: function() {
- this.setState({
- cost: null,
- isEstimate: null,
- });
- },
-
- componentDidMount: function() {
- this._isMounted = true;
- lbry.getCostInfo(this.props.uri).then(({cost, includesData}) => {
- if (this._isMounted) {
- this.setState({
- cost: cost,
- isEstimate: !includesData,
- });
- }
- }, (err) => {
- // If we get an error looking up cost information, do nothing
- });
- },
-
- componentWillUnmount: function() {
- this._isMounted = false;
- },
-
- render: function() {
- if (this.state.cost === null) {
- return ??? ;
- }
-
- return
- }
-});
-
var addressStyle = {
fontFamily: '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace',
};
diff --git a/ui/js/component/fileActions/index.js b/ui/js/component/fileActions/index.js
index d17e57af8..19e66dfdb 100644
--- a/ui/js/component/fileActions/index.js
+++ b/ui/js/component/fileActions/index.js
@@ -6,16 +6,62 @@ import {
selectObscureNsfw,
selectHidePrice,
selectHasSignature,
+ selectPlatform,
} from 'selectors/app'
+import {
+ makeSelectFileInfoForUri,
+ makeSelectDownloadingForUri,
+ makeSelectLoadingForUri,
+} from 'selectors/file_info'
+import {
+ makeSelectAvailabilityForUri,
+} from 'selectors/availability'
+import {
+ selectCurrentModal,
+} from 'selectors/app'
+import {
+ doCloseModal,
+ doOpenModal,
+} from 'actions/app'
+import {
+ doOpenFileInShell,
+ doOpenFileInFolder,
+ doDeleteFile,
+} from 'actions/file_info'
+import {
+ doWatchVideo,
+} from 'actions/content'
import FileActions from './view'
-const select = (state) => ({
- obscureNsfw: selectObscureNsfw(state),
- hidePrice: selectHidePrice(state),
- hasSignature: selectHasSignature(state),
-})
+const makeSelect = () => {
+ const selectFileInfoForUri = makeSelectFileInfoForUri()
+ const selectAvailabilityForUri = makeSelectAvailabilityForUri()
+ const selectDownloadingForUri = makeSelectDownloadingForUri()
+ const selectLoadingForUri = makeSelectLoadingForUri()
-const perform = {
+ const select = (state, props) => ({
+ obscureNsfw: selectObscureNsfw(state),
+ hidePrice: selectHidePrice(state),
+ hasSignature: selectHasSignature(state),
+ fileInfo: selectFileInfoForUri(state, props),
+ availability: selectAvailabilityForUri(state, props),
+ platform: selectPlatform(state),
+ modal: selectCurrentModal(state),
+ downloading: selectDownloadingForUri(state, props),
+ loading: selectLoadingForUri(state, props),
+ })
+
+ return select
}
-export default connect(select, perform)(FileActions)
+const perform = (dispatch) => ({
+ closeModal: () => dispatch(doCloseModal()),
+ openInFolder: (fileInfo) => dispatch(doOpenFileInFolder(fileInfo)),
+ openInShell: (fileInfo) => dispatch(doOpenFileInShell(fileInfo)),
+ affirmPurchase: () => console.log('affirm purchase'),
+ deleteFile: (fileInfo, deleteFromComputer) => dispatch(doDeleteFile(fileInfo, deleteFromComputer)),
+ openModal: (modal) => dispatch(doOpenModal(modal)),
+ downloadClick: () => dispatch(doWatchVideo()),
+})
+
+export default connect(makeSelect, perform)(FileActions)
diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx
index 96267dbd8..8b880502d 100644
--- a/ui/js/component/fileActions/view.jsx
+++ b/ui/js/component/fileActions/view.jsx
@@ -1,149 +1,66 @@
import React from 'react';
import lbry from 'lbry';
import lbryuri from 'lbryuri';
-import {Icon, FilePrice} from 'component/common';
+import {Icon,} from 'component/common';
+import FilePrice from 'component/filePrice'
import {Modal} from 'component/modal';
import {FormField} from 'component/form';
import Link from 'component/link';
import {ToolTip} from 'component/tooltip';
import {DropDownMenu, DropDownMenuItem} from 'component/menu';
-const {shell} = require('electron');
-
-const FileActionsRow = React.createClass({
- _isMounted: false,
- _fileInfoSubscribeId: null,
-
- propTypes: {
- uri: React.PropTypes.string,
- outpoint: React.PropTypes.string.isRequired,
- metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
- contentType: React.PropTypes.string.isRequired,
- },
- getInitialState: function() {
- return {
- fileInfo: null,
- modal: null,
- menuOpen: false,
+class FileActionsRow extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
deleteChecked: false,
- attemptingDownload: false,
- attemptingRemove: false,
}
- },
- onFileInfoUpdate: function(fileInfo) {
- if (this._isMounted) {
- this.setState({
- fileInfo: fileInfo ? fileInfo : false,
- attemptingDownload: fileInfo ? false : this.state.attemptingDownload
- });
- }
- },
- tryDownload: function() {
- this.setState({
- attemptingDownload: true,
- attemptingRemove: false
- });
- lbry.getCostInfo(this.props.uri).then(({cost}) => {
- lbry.getBalance((balance) => {
- if (cost > balance) {
- this.setState({
- modal: 'notEnoughCredits',
- attemptingDownload: false,
- });
- } else if (this.state.affirmedPurchase) {
- lbry.get({uri: this.props.uri}).then((streamInfo) => {
- if (streamInfo === null || typeof streamInfo !== 'object') {
- this.setState({
- modal: 'timedOut',
- attemptingDownload: false,
- });
- }
- });
- } else {
- this.setState({
- attemptingDownload: false,
- modal: 'affirmPurchase'
- })
- }
- });
- });
- },
- closeModal: function() {
- this.setState({
- modal: null,
- })
- },
- onDownloadClick: function() {
- if (!this.state.fileInfo && !this.state.attemptingDownload) {
- this.tryDownload();
- }
- },
- onOpenClick: function() {
- if (this.state.fileInfo && this.state.fileInfo.download_path) {
- shell.openItem(this.state.fileInfo.download_path);
- }
- },
- handleDeleteCheckboxClicked: function(event) {
+ }
+
+ handleDeleteCheckboxClicked(event) {
this.setState({
deleteChecked: event.target.checked,
- });
- },
- handleRevealClicked: function() {
- if (this.state.fileInfo && this.state.fileInfo.download_path) {
- shell.showItemInFolder(this.state.fileInfo.download_path);
- }
- },
- handleRemoveClicked: function() {
- this.setState({
- modal: 'confirmRemove',
- });
- },
- handleRemoveConfirmed: function() {
- lbry.removeFile(this.props.outpoint, this.state.deleteChecked);
- this.setState({
- modal: null,
- fileInfo: false,
- attemptingDownload: false
- });
- },
- onAffirmPurchase: function() {
- this.setState({
- affirmedPurchase: true,
- modal: null
- });
- this.tryDownload();
- },
- openMenu: function() {
- this.setState({
- menuOpen: !this.state.menuOpen,
- });
- },
- componentDidMount: function() {
- this._isMounted = true;
- this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
- },
- componentWillUnmount: function() {
- this._isMounted = false;
- if (this._fileInfoSubscribeId) {
- lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
- }
- },
- render: function() {
- if (this.state.fileInfo === null)
+ })
+ }
+
+ render() {
+ const {
+ fileInfo,
+ platform,
+ downloading,
+ loading,
+ uri,
+ deleteFile,
+ openInFolder,
+ openInShell,
+ modal,
+ openModal,
+ affirmPurchase,
+ closeModal,
+ downloadClick,
+ } = this.props
+
+ const {
+ deleteChecked,
+ } = this.state
+
+ const metadata = fileInfo ? fileInfo.metadata : null
+
+ if (!fileInfo)
{
return null;
}
- const openInFolderMessage = window.navigator.platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder',
- showMenu = !!this.state.fileInfo;
+ const openInFolderMessage = platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder',
+ showMenu = Object.keys(fileInfo).length != 0;
let linkBlock;
- if (this.state.fileInfo === false && !this.state.attemptingDownload) {
- linkBlock = ;
- } else if (this.state.attemptingDownload || (!this.state.fileInfo.completed && !this.state.fileInfo.isMine)) {
+ if (Object.keys(fileInfo).length == 0 && !downloading && !loading) {
+ linkBlock = ;
+ } else if (downloading || loading) {
const
- progress = this.state.fileInfo ? this.state.fileInfo.written_bytes / this.state.fileInfo.total_bytes * 100 : 0,
- label = this.state.fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...',
+ progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
+ label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...',
labelWithIcon = {label} ;
linkBlock = (
@@ -153,101 +70,253 @@ const FileActionsRow = React.createClass({
);
} else {
- linkBlock = ;
+ linkBlock = openInShell(fileInfo)} />;
}
- const uri = lbryuri.normalize(this.props.uri);
- const title = this.props.metadata ? this.props.metadata.title : uri;
+ const title = metadata ? metadata.title : uri;
return (
- {this.state.fileInfo !== null || this.state.fileInfo.isMine
+ {fileInfo !== null || fileInfo.isMine
? linkBlock
: null}
{ showMenu ?
-
-
+ openInFolder(fileInfo)} label={openInFolderMessage} />
+ openModal('confirmRemove')} label="Remove..." />
: '' }
-
- Are you sure you'd like to buy {title} for credits?
+
+ Are you sure you'd like to buy {title} for credits?
-
+
You don't have enough LBRY credits to pay for this stream.
-
+
LBRY was unable to download the stream {uri} .
-
+ deleteFile(uri, fileInfo, deleteChecked)}
+ onAborted={closeModal}>
Are you sure you'd like to remove {title} from LBRY?
- Delete this file from my computer
+ Delete this file from my computer
);
}
-});
+}
-const FileActions = React.createClass({
- _isMounted: false,
- _fileInfoSubscribeId: null,
+// const FileActionsRow = React.createClass({
+// _isMounted: false,
+// _fileInfoSubscribeId: null,
- propTypes: {
- uri: React.PropTypes.string,
- outpoint: React.PropTypes.string.isRequired,
- metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
- contentType: React.PropTypes.string,
- },
- getInitialState: function() {
- return {
+// propTypes: {
+// uri: React.PropTypes.string,
+// outpoint: React.PropTypes.string.isRequired,
+// metadata: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]),
+// contentType: React.PropTypes.string.isRequired,
+// },
+// getInitialState: function() {
+// return {
+// fileInfo: null,
+// modal: null,
+// menuOpen: false,
+// deleteChecked: false,
+// attemptingDownload: false,
+// attemptingRemove: false,
+// }
+// },
+// onFileInfoUpdate: function(fileInfo) {
+// if (this._isMounted) {
+// this.setState({
+// fileInfo: fileInfo ? fileInfo : false,
+// attemptingDownload: fileInfo ? false : this.state.attemptingDownload
+// });
+// }
+// },
+// tryDownload: function() {
+// this.setState({
+// attemptingDownload: true,
+// attemptingRemove: false
+// });
+// lbry.getCostInfo(this.props.uri).then(({cost}) => {
+// lbry.getBalance((balance) => {
+// if (cost > balance) {
+// this.setState({
+// modal: 'notEnoughCredits',
+// attemptingDownload: false,
+// });
+// } else if (this.state.affirmedPurchase) {
+// lbry.get({uri: this.props.uri}).then((streamInfo) => {
+// if (streamInfo === null || typeof streamInfo !== 'object') {
+// this.setState({
+// modal: 'timedOut',
+// attemptingDownload: false,
+// });
+// }
+// });
+// } else {
+// this.setState({
+// attemptingDownload: false,
+// modal: 'affirmPurchase'
+// })
+// }
+// });
+// });
+// },
+// closeModal: function() {
+// this.setState({
+// modal: null,
+// })
+// },
+// onDownloadClick: function() {
+// if (!this.state.fileInfo && !this.state.attemptingDownload) {
+// this.tryDownload();
+// }
+// },
+// onOpenClick: function() {
+// if (this.state.fileInfo && this.state.fileInfo.download_path) {
+// shell.openItem(this.state.fileInfo.download_path);
+// }
+// },
+// handleDeleteCheckboxClicked: function(event) {
+// this.setState({
+// deleteChecked: event.target.checked,
+// });
+// },
+// handleRevealClicked: function() {
+// if (this.state.fileInfo && this.state.fileInfo.download_path) {
+// shell.showItemInFolder(this.state.fileInfo.download_path);
+// }
+// },
+// handleRemoveClicked: function() {
+// this.setState({
+// modal: 'confirmRemove',
+// });
+// },
+// handleRemoveConfirmed: function() {
+// lbry.removeFile(this.props.outpoint, this.state.deleteChecked);
+// this.setState({
+// modal: null,
+// fileInfo: false,
+// attemptingDownload: false
+// });
+// },
+// onAffirmPurchase: function() {
+// this.setState({
+// affirmedPurchase: true,
+// modal: null
+// });
+// this.tryDownload();
+// },
+// openMenu: function() {
+// this.setState({
+// menuOpen: !this.state.menuOpen,
+// });
+// },
+// componentDidMount: function() {
+// this._isMounted = true;
+// this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
+// },
+// componentWillUnmount: function() {
+// this._isMounted = false;
+// if (this._fileInfoSubscribeId) {
+// lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
+// }
+// },
+// render: function() {
+// if (this.state.fileInfo === null)
+// {
+// return null;
+// }
+
+// const openInFolderMessage = window.navigator.platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder',
+// showMenu = !!this.state.fileInfo;
+
+// let linkBlock;
+// if (this.state.fileInfo === false && !this.state.attemptingDownload) {
+// linkBlock = ;
+// } else if (this.state.attemptingDownload || (!this.state.fileInfo.completed && !this.state.fileInfo.isMine)) {
+// const
+// progress = this.state.fileInfo ? this.state.fileInfo.written_bytes / this.state.fileInfo.total_bytes * 100 : 0,
+// label = this.state.fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...',
+// labelWithIcon = {label} ;
+
+// linkBlock = (
+//
+//
{labelWithIcon}
+// {labelWithIcon}
+//
+// );
+// } else {
+// linkBlock = ;
+// }
+
+// const uri = lbryuri.normalize(this.props.uri);
+// const title = this.props.metadata ? this.props.metadata.title : uri;
+// return (
+//
+// {this.state.fileInfo !== null || this.state.fileInfo.isMine
+// ? linkBlock
+// : null}
+// { showMenu ?
+//
+//
+//
+// : '' }
+//
+// Are you sure you'd like to buy {title} for credits?
+//
+//
+// You don't have enough LBRY credits to pay for this stream.
+//
+//
+// LBRY was unable to download the stream {uri} .
+//
+//
+// Are you sure you'd like to remove {title} from LBRY?
+
+// Delete this file from my computer
+//
+//
+// );
+// }
+// });
+
+class FileActions extends React.Component {
+ constructor(props) {
+ super(props)
+ this._isMounted = false
+ this._fileInfoSubscribeId = null
+ this.state = {
available: true,
forceShowActions: false,
fileInfo: null,
}
- },
- onShowFileActionsRowClicked: function() {
+ }
+
+ onShowFileActionsRowClicked() {
this.setState({
forceShowActions: true,
});
- },
- onFileInfoUpdate: function(fileInfo) {
- if (this.isMounted) {
- this.setState({
- fileInfo: fileInfo,
- });
- }
- },
- componentDidMount: function() {
- this._isMounted = true;
- this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
+ }
+
+ render() {
+ const {
+ fileInfo,
+ availability,
+ } = this.props
- lbry.get_availability({uri: this.props.uri}, (availability) => {
- if (this._isMounted) {
- this.setState({
- available: availability > 0,
- });
- }
- }, () => {
- // Take any error to mean the file is unavailable
- if (this._isMounted) {
- this.setState({
- available: false,
- });
- }
- });
- },
- componentWillUnmount: function() {
- this._isMounted = false;
- if (this._fileInfoSubscribeId) {
- lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
- }
- },
- render: function() {
- const fileInfo = this.state.fileInfo;
if (fileInfo === null) {
return null;
}
@@ -255,18 +324,17 @@ const FileActions = React.createClass({
return (
{
fileInfo || this.state.available || this.state.forceShowActions
- ?
+ ?
:
}
);
}
-});
+}
export default FileActions
diff --git a/ui/js/component/fileCardStream/view.jsx b/ui/js/component/fileCardStream/view.jsx
index d2bd9a1c3..a3b6d9b56 100644
--- a/ui/js/component/fileCardStream/view.jsx
+++ b/ui/js/component/fileCardStream/view.jsx
@@ -2,7 +2,8 @@ import React from 'react';
import lbry from 'lbry.js';
import lbryuri from 'lbryuri.js';
import Link from 'component/link';
-import {Thumbnail, TruncatedText, FilePrice} from 'component/common';
+import {Thumbnail, TruncatedText,} from 'component/common';
+import FilePrice from 'component/filePrice'
import UriIndicator from 'component/channel-indicator';
class FileCardStream extends React.Component {
@@ -72,7 +73,7 @@ class FileCardStream extends React.Component {
{title}
- { !this.props.hidePrice ? : null}
+ { !this.props.hidePrice ? : null}
diff --git a/ui/js/component/filePrice/index.js b/ui/js/component/filePrice/index.js
new file mode 100644
index 000000000..c5a9497d0
--- /dev/null
+++ b/ui/js/component/filePrice/index.js
@@ -0,0 +1,22 @@
+import React from 'react'
+import {
+ connect,
+} from 'react-redux'
+import {
+ makeSelectCostInfoForUri,
+} from 'selectors/cost_info'
+import FilePrice from './view'
+
+const makeSelect = () => {
+ const selectCostInfoForUri = makeSelectCostInfoForUri()
+ const select = (state, props) => ({
+ costInfo: selectCostInfoForUri(state, props),
+ })
+
+ return select
+}
+
+const perform = (dispatch) => ({
+})
+
+export default connect(makeSelect, perform)(FilePrice)
diff --git a/ui/js/component/filePrice/view.jsx b/ui/js/component/filePrice/view.jsx
new file mode 100644
index 000000000..17b830bf2
--- /dev/null
+++ b/ui/js/component/filePrice/view.jsx
@@ -0,0 +1,21 @@
+import React from 'react'
+import {
+ CreditAmount,
+} from 'component/common'
+
+const FilePrice = (props) => {
+ const {
+ costInfo,
+ look = 'indicator',
+ } = props
+
+ const isEstimate = costInfo ? !costInfo.includesData : null
+
+ if (!costInfo) {
+ return
??? ;
+ }
+
+ return
+}
+
+export default FilePrice
diff --git a/ui/js/component/fileTileStream/view.jsx b/ui/js/component/fileTileStream/view.jsx
index f5a0c218a..fd3a2b32c 100644
--- a/ui/js/component/fileTileStream/view.jsx
+++ b/ui/js/component/fileTileStream/view.jsx
@@ -3,7 +3,8 @@ import lbry from 'lbry.js';
import lbryuri from 'lbryuri.js';
import Link from 'component/link';
import FileActions from 'component/fileActions';
-import {Thumbnail, TruncatedText, FilePrice} from 'component/common.js';
+import {Thumbnail, TruncatedText,} from 'component/common.js';
+import FilePrice from 'component/filePrice'
import UriIndicator from 'component/channel-indicator.js';
/*should be merged into FileTile once FileTile is refactored to take a single id*/
diff --git a/ui/js/component/video/index.js b/ui/js/component/video/index.js
index e258e55f7..94978f702 100644
--- a/ui/js/component/video/index.js
+++ b/ui/js/component/video/index.js
@@ -16,8 +16,6 @@ import {
selectLoadingCurrentUri,
selectCurrentUriFileReadyToPlay,
selectCurrentUriIsPlaying,
-} from 'selectors/content'
-import {
selectCurrentUriFileInfo,
selectDownloadingCurrentUri,
} from 'selectors/file_info'
diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js
index cb5657d59..f00739ade 100644
--- a/ui/js/constants/action_types.js
+++ b/ui/js/constants/action_types.js
@@ -56,6 +56,8 @@ 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'
// Search
export const SEARCH_STARTED = 'SEARCH_STARTED'
diff --git a/ui/js/lbry.js b/ui/js/lbry.js
index d3c02e231..630f6db63 100644
--- a/ui/js/lbry.js
+++ b/ui/js/lbry.js
@@ -301,7 +301,7 @@ lbry.getMyClaims = function(callback) {
lbry.removeFile = function(outpoint, deleteTargetFile=true, callback) {
this._removedFiles.push(outpoint);
- this._updateFileInfoSubscribers(outpoint);
+ // this._updateFileInfoSubscribers(outpoint);
lbry.file_delete({
outpoint: outpoint,
diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx
index 9ba48cbf3..2a3498bf9 100644
--- a/ui/js/page/showPage/view.jsx
+++ b/ui/js/page/showPage/view.jsx
@@ -6,9 +6,9 @@ import Video from 'component/video'
import {
TruncatedText,
Thumbnail,
- FilePrice,
- BusyMessage
-} from 'component/common.js';
+ BusyMessage,
+} from 'component/common';
+import FilePrice from 'component/filePrice'
import FileActions from 'component/fileActions';
import Link from 'component/link';
import UriIndicator from 'component/channel-indicator.js';
@@ -121,7 +121,7 @@ let FilePage = React.createClass({
render: function() {
const metadata = this.props.metadata,
title = metadata ? this.props.metadata.title : this.props.uri,
- uriIndicator =
;
+ uriIndicator =
return (
@@ -134,14 +134,14 @@ let FilePage = React.createClass({
{this.state.isDownloaded === false
- ?
+ ?
: null}
{title}
{ this.props.channelUri ?
{uriIndicator} :
uriIndicator}
-
+
@@ -288,4 +288,6 @@ let ShowPage = React.createClass({
return
{innerContent} ;
}
-});
\ No newline at end of file
+});
+
+export default ShowPage;
diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js
index a5e4eba74..6c36daf0c 100644
--- a/ui/js/reducers/content.js
+++ b/ui/js/reducers/content.js
@@ -96,36 +96,6 @@ reducers[types.FETCH_PUBLISHED_CONTENT_COMPLETED] = function(state, action) {
})
}
-reducers[types.LOADING_VIDEO_STARTED] = function(state, action) {
- const {
- uri,
- } = action.data
- const newLoading = Object.assign({}, state.loading)
- const newByUri = Object.assign({}, newLoading.byUri)
-
- newByUri[uri] = true
- newLoading.byUri = newByUri
-
- return Object.assign({}, state, {
- loading: newLoading,
- })
-}
-
-reducers[types.LOADING_VIDEO_FAILED] = function(state, action) {
- const {
- uri,
- } = action.data
- const newLoading = Object.assign({}, state.loading)
- const newByUri = Object.assign({}, newLoading.byUri)
-
- delete newByUri[uri]
- newLoading.byUri = newByUri
-
- return Object.assign({}, state, {
- loading: newLoading,
- })
-}
-
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 1467f0ee8..2c98cf048 100644
--- a/ui/js/reducers/file_info.js
+++ b/ui/js/reducers/file_info.js
@@ -41,13 +41,20 @@ reducers[types.DOWNLOADING_STARTED] = function(state, action) {
} = action.data
const newByUri = Object.assign({}, state.byUri)
const newDownloading = Object.assign({}, state.downloading)
+ const newDownloadingByUri = Object.assign({}, newDownloading.byUri)
+ const newLoading = Object.assign({}, state.loading)
+ const newLoadingByUri = Object.assign({}, newLoading)
- newDownloading[uri] = true
+ newDownloadingByUri[uri] = true
+ newDownloading.byUri = newDownloadingByUri
newByUri[uri] = fileInfo
+ delete newLoadingByUri[uri]
+ newLoading.byUri = newLoadingByUri
return Object.assign({}, state, {
downloading: newDownloading,
byUri: newByUri,
+ loading: newLoading,
})
}
@@ -75,13 +82,78 @@ reducers[types.DOWNLOADING_COMPLETED] = function(state, action) {
} = action.data
const newByUri = Object.assign({}, state.byUri)
const newDownloading = Object.assign({}, state.downloading)
+ const newDownloadingByUri = Object.assign({}, newDownloading.byUri)
newByUri[uri] = fileInfo
- delete newDownloading[uri]
+ delete newDownloadingByUri[uri]
+ newDownloading.byUri = newDownloadingByUri
return Object.assign({}, state, {
byUri: newByUri,
- downloading: newDownloading
+ downloading: newDownloading,
+ })
+}
+
+reducers[types.DELETE_FILE_STARTED] = function(state, action) {
+ const {
+ uri,
+ } = action.data
+ const newDeleting = Object.assign({}, state.deleting)
+ const newByUri = Object.assign({}, newDeleting.byUri)
+
+ newByUri[uri] = true
+ newDeleting.byUri = newByUri
+
+ 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 newByUri = Object.assign({}, state.byUri)
+
+ delete newDeletingByUri[uri]
+ newDeleting.byUri = newDeletingByUri
+ delete newByUri[uri]
+
+ return Object.assign({}, state, {
+ deleting: newDeleting,
+ byUri: newByUri,
+ })
+}
+
+reducers[types.LOADING_VIDEO_STARTED] = function(state, action) {
+ const {
+ uri,
+ } = action.data
+ const newLoading = Object.assign({}, state.loading)
+ const newByUri = Object.assign({}, newLoading.byUri)
+
+ newByUri[uri] = true
+ newLoading.byUri = newByUri
+
+ return Object.assign({}, state, {
+ loading: newLoading,
+ })
+}
+
+reducers[types.LOADING_VIDEO_FAILED] = function(state, action) {
+ const {
+ uri,
+ } = action.data
+ const newLoading = Object.assign({}, state.loading)
+ const newByUri = Object.assign({}, newLoading.byUri)
+
+ delete newByUri[uri]
+ newLoading.byUri = newByUri
+
+ return Object.assign({}, state, {
+ loading: newLoading,
})
}
diff --git a/ui/js/selectors/availability.js b/ui/js/selectors/availability.js
index 0588c1528..7aeaa6330 100644
--- a/ui/js/selectors/availability.js
+++ b/ui/js/selectors/availability.js
@@ -1,6 +1,11 @@
import {
createSelector,
} from 'reselect'
+import {
+ selectDaemonReady,
+ selectCurrentPage,
+ selectCurrentUri,
+} from 'selectors/app'
const _selectState = state => state.availability
@@ -40,3 +45,30 @@ export const makeSelectFetchingAvailabilityForUri = () => {
(fetching) => fetching
)
}
+
+export const selectFetchingAvailabilityForCurrentUri = createSelector(
+ selectCurrentUri,
+ selectFetchingAvailabilityByUri,
+ (uri, byUri) => byUri[uri]
+)
+
+export const selectAvailabilityForCurrentUri = createSelector(
+ selectCurrentUri,
+ selectAvailabilityByUri,
+ (uri, byUri) => byUri[uri]
+)
+
+export const shouldFetchCurrentUriAvailability = createSelector(
+ selectDaemonReady,
+ selectCurrentPage,
+ selectFetchingAvailabilityForCurrentUri,
+ selectAvailabilityForCurrentUri,
+ (daemonReady, page, fetching, availability) => {
+ if (!daemonReady) return false
+ if (page != 'show') return false
+ if (fetching) return false
+ if (availability) return false
+
+ return true
+ }
+)
diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js
index c8c7a1386..be38c21b3 100644
--- a/ui/js/selectors/content.js
+++ b/ui/js/selectors/content.js
@@ -4,14 +4,6 @@ import {
selectCurrentPage,
selectCurrentUri,
} from 'selectors/app'
-import {
- selectCurrentUriCostInfo,
- selectFetchingCurrentUriCostInfo,
-} from 'selectors/cost_info'
-import {
- selectCurrentUriFileInfo,
- selectFetchingCurrentUriFileInfo,
-} from 'selectors/file_info'
export const _selectState = state => state.content || {}
@@ -50,13 +42,6 @@ export const selectFetchingFileInfos = createSelector(
(state) => state.fetchingFileInfos || {}
)
-// 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
-)
-
export const selectFetchingDownloadedContent = createSelector(
_selectState,
(state) => !!state.fetchingDownloadedContent
@@ -97,22 +82,6 @@ export const selectPublishedContent = createSelector(
(state) => state.publishedContent || {}
)
-export const selectLoading = createSelector(
- _selectState,
- (state) => state.loading || {}
-)
-
-export const selectLoadingByUri = createSelector(
- selectLoading,
- (loading) => loading.byUri || {}
-)
-
-export const selectLoadingCurrentUri = createSelector(
- selectLoadingByUri,
- selectCurrentUri,
- (byUri, uri) => !!byUri[uri]
-)
-
export const shouldFetchPublishedContent = createSelector(
selectDaemonReady,
selectCurrentPage,
diff --git a/ui/js/selectors/cost_info.js b/ui/js/selectors/cost_info.js
index 55a1416ea..d250aaf19 100644
--- a/ui/js/selectors/cost_info.js
+++ b/ui/js/selectors/cost_info.js
@@ -42,3 +42,13 @@ export const shouldFetchCurrentUriCostInfo = createSelector(
}
)
+const selectCostInfoForUri = (state, props) => {
+ return selectAllCostInfoByUri(state)[props.uri]
+}
+
+export const makeSelectCostInfoForUri = () => {
+ return createSelector(
+ selectCostInfoForUri,
+ (costInfo) => costInfo
+ )
+}
diff --git a/ui/js/selectors/file_info.js b/ui/js/selectors/file_info.js
index c26b5dcc8..79b28c1d6 100644
--- a/ui/js/selectors/file_info.js
+++ b/ui/js/selectors/file_info.js
@@ -54,7 +54,11 @@ export const selectDownloadingCurrentUri = createSelector(
export const selectCurrentUriIsDownloaded = createSelector(
selectCurrentUriFileInfo,
(fileInfo) => {
- return fileInfo && (fileInfo.written_bytes > 0 || fileInfo.completed)
+ if (!fileInfo) return false
+ if (!fileInfo.completed) return false
+ if (!fileInfo.written_bytes > 0) return false
+
+ return true
}
)
@@ -82,3 +86,50 @@ export const makeSelectFileInfoForUri = () => {
(fileInfo) => fileInfo
)
}
+
+const selectDownloadingForUri = (state, props) => {
+ const byUri = selectDownloadingByUri(state)
+ return byUri[props.uri]
+}
+
+export const makeSelectDownloadingForUri = () => {
+ return createSelector(
+ selectDownloadingForUri,
+ (downloadingForUri) => !!downloadingForUri
+ )
+}
+
+export const selectLoading = createSelector(
+ _selectState,
+ (state) => state.loading || {}
+)
+
+export const selectLoadingByUri = createSelector(
+ selectLoading,
+ (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]
+}
+
+export const makeSelectLoadingForUri = () => {
+ return createSelector(
+ selectLoadingForUri,
+ (loading) => !!loading
+ )
+}
diff --git a/ui/js/triggers.js b/ui/js/triggers.js
index 0d35f97d7..41d0e0763 100644
--- a/ui/js/triggers.js
+++ b/ui/js/triggers.js
@@ -13,6 +13,9 @@ import {
import {
shouldFetchCurrentUriCostInfo,
} from 'selectors/cost_info'
+import {
+ shouldFetchCurrentUriAvailability,
+} from 'selectors/availability'
import {
doFetchTransactions,
doGetNewAddress,
@@ -28,6 +31,9 @@ import {
import {
doFetchCurrentUriCostInfo,
} from 'actions/cost_info'
+import {
+ doFetchCurrentUriAvailability,
+} from 'actions/availability'
const triggers = []
@@ -66,6 +72,11 @@ triggers.push({
action: doFetchCurrentUriCostInfo,
})
+triggers.push({
+ selector: shouldFetchCurrentUriAvailability,
+ action: doFetchCurrentUriAvailability,
+})
+
const runTriggers = function() {
triggers.forEach(function(trigger) {
const state = app.store.getState();