Redux #115
22 changed files with 635 additions and 334 deletions
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <span className={`credit-amount credit-amount--${this.props.look}`}>???</span>;
|
||||
}
|
||||
|
||||
return <CreditAmount label={false} amount={this.state.cost} isEstimate={this.state.isEstimate} showFree={true} />
|
||||
}
|
||||
});
|
||||
|
||||
var addressStyle = {
|
||||
fontFamily: '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace',
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = <Link button="text" label="Download" icon="icon-download" onClick={this.onDownloadClick} />;
|
||||
} else if (this.state.attemptingDownload || (!this.state.fileInfo.completed && !this.state.fileInfo.isMine)) {
|
||||
if (Object.keys(fileInfo).length == 0 && !downloading && !loading) {
|
||||
linkBlock = <Link button="text" label="Download" icon="icon-download" onClick={downloadClick} />;
|
||||
} 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 = <span className="button__content"><Icon icon="icon-download" /><span>{label}</span></span>;
|
||||
|
||||
linkBlock = (
|
||||
|
@ -153,101 +70,253 @@ const FileActionsRow = React.createClass({
|
|||
</div>
|
||||
);
|
||||
} else {
|
||||
linkBlock = <Link label="Open" button="text" icon="icon-folder-open" onClick={this.onOpenClick} />;
|
||||
linkBlock = <Link label="Open" button="text" icon="icon-folder-open" onClick={() => 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 (
|
||||
<div>
|
||||
{this.state.fileInfo !== null || this.state.fileInfo.isMine
|
||||
{fileInfo !== null || fileInfo.isMine
|
||||
? linkBlock
|
||||
: null}
|
||||
{ showMenu ?
|
||||
<DropDownMenu>
|
||||
<DropDownMenuItem key={0} onClick={this.handleRevealClicked} label={openInFolderMessage} />
|
||||
<DropDownMenuItem key={1} onClick={this.handleRemoveClicked} label="Remove..." />
|
||||
<DropDownMenuItem key={0} onClick={() => openInFolder(fileInfo)} label={openInFolderMessage} />
|
||||
<DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label="Remove..." />
|
||||
</DropDownMenu> : '' }
|
||||
<Modal type="confirm" isOpen={this.state.modal == 'affirmPurchase'}
|
||||
contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase} onAborted={this.closeModal}>
|
||||
Are you sure you'd like to buy <strong>{title}</strong> for <strong><FilePrice uri={uri} metadata={this.props.metadata} label={false} look="plain" /></strong> credits?
|
||||
<Modal type="confirm" isOpen={modal == 'affirmPurchase'}
|
||||
contentLabel="Confirm Purchase" onConfirmed={affirmPurchase} onAborted={closeModal}>
|
||||
Are you sure you'd like to buy <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits?
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'notEnoughCredits'} contentLabel="Not enough credits"
|
||||
onConfirmed={this.closeModal}>
|
||||
<Modal isOpen={modal == 'notEnoughCredits'} contentLabel="Not enough credits"
|
||||
onConfirmed={closeModal}>
|
||||
You don't have enough LBRY credits to pay for this stream.
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'timedOut'} contentLabel="Download failed"
|
||||
onConfirmed={this.closeModal}>
|
||||
<Modal isOpen={modal == 'timedOut'} contentLabel="Download failed"
|
||||
onConfirmed={closeModal}>
|
||||
LBRY was unable to download the stream <strong>{uri}</strong>.
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'confirmRemove'} contentLabel="Not enough credits"
|
||||
type="confirm" confirmButtonLabel="Remove" onConfirmed={this.handleRemoveConfirmed}
|
||||
onAborted={this.closeModal}>
|
||||
<Modal isOpen={modal == 'confirmRemove'}
|
||||
contentLabel="Not enough credits"
|
||||
type="confirm"
|
||||
confirmButtonLabel="Remove"
|
||||
onConfirmed={() => deleteFile(uri, fileInfo, deleteChecked)}
|
||||
onAborted={closeModal}>
|
||||
<p>Are you sure you'd like to remove <cite>{title}</cite> from LBRY?</p>
|
||||
|
||||
<label><FormField type="checkbox" checked={this.state.deleteChecked} onClick={this.handleDeleteCheckboxClicked} /> Delete this file from my computer</label>
|
||||
<label><FormField type="checkbox" checked={deleteChecked} onClick={this.handleDeleteCheckboxClicked.bind(this)} /> Delete this file from my computer</label>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 = <Link button="text" label="Download" icon="icon-download" onClick={this.onDownloadClick} />;
|
||||
// } 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 = <span className="button__content"><Icon icon="icon-download" /><span>{label}</span></span>;
|
||||
|
||||
// linkBlock = (
|
||||
// <div className="faux-button-block file-actions__download-status-bar button-set-item">
|
||||
// <div className="faux-button-block file-actions__download-status-bar-overlay" style={{ width: progress + '%' }}>{labelWithIcon}</div>
|
||||
// {labelWithIcon}
|
||||
// </div>
|
||||
// );
|
||||
// } else {
|
||||
// linkBlock = <Link label="Open" button="text" icon="icon-folder-open" onClick={this.onOpenClick} />;
|
||||
// }
|
||||
|
||||
// const uri = lbryuri.normalize(this.props.uri);
|
||||
// const title = this.props.metadata ? this.props.metadata.title : uri;
|
||||
// return (
|
||||
// <div>
|
||||
// {this.state.fileInfo !== null || this.state.fileInfo.isMine
|
||||
// ? linkBlock
|
||||
// : null}
|
||||
// { showMenu ?
|
||||
// <DropDownMenu>
|
||||
// <DropDownMenuItem key={0} onClick={this.handleRevealClicked} label={openInFolderMessage} />
|
||||
// <DropDownMenuItem key={1} onClick={this.handleRemoveClicked} label="Remove..." />
|
||||
// </DropDownMenu> : '' }
|
||||
// <Modal type="confirm" isOpen={this.state.modal == 'affirmPurchase'}
|
||||
// contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase} onAborted={this.closeModal}>
|
||||
// Are you sure you'd like to buy <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits?
|
||||
// </Modal>
|
||||
// <Modal isOpen={this.state.modal == 'notEnoughCredits'} contentLabel="Not enough credits"
|
||||
// onConfirmed={this.closeModal}>
|
||||
// You don't have enough LBRY credits to pay for this stream.
|
||||
// </Modal>
|
||||
// <Modal isOpen={this.state.modal == 'timedOut'} contentLabel="Download failed"
|
||||
// onConfirmed={this.closeModal}>
|
||||
// LBRY was unable to download the stream <strong>{uri}</strong>.
|
||||
// </Modal>
|
||||
// <Modal isOpen={this.state.modal == 'confirmRemove'} contentLabel="Not enough credits"
|
||||
// type="confirm" confirmButtonLabel="Remove" onConfirmed={this.handleRemoveConfirmed}
|
||||
// onAborted={this.closeModal}>
|
||||
// <p>Are you sure you'd like to remove <cite>{title}</cite> from LBRY?</p>
|
||||
|
||||
// <label><FormField type="checkbox" checked={this.state.deleteChecked} onClick={this.handleDeleteCheckboxClicked} /> Delete this file from my computer</label>
|
||||
// </Modal>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
|
||||
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 (<section className="file-actions">
|
||||
{
|
||||
fileInfo || this.state.available || this.state.forceShowActions
|
||||
? <FileActionsRow outpoint={this.props.outpoint} metadata={this.props.metadata} uri={this.props.uri}
|
||||
contentType={this.props.contentType} />
|
||||
? <FileActionsRow {...this.props} />
|
||||
: <div>
|
||||
<div className="button-set-item empty">Content unavailable.</div>
|
||||
<ToolTip label="Why?"
|
||||
body="The content on LBRY is hosted by its users. It appears there are no users connected that have this file at the moment."
|
||||
className="button-set-item" />
|
||||
<Link label="Try Anyway" onClick={this.onShowFileActionsRowClicked} className="button-text button-set-item" />
|
||||
<Link label="Try Anyway" onClick={this.onShowFileActionsRowClicked.bind(this)} className="button-text button-set-item" />
|
||||
</div>
|
||||
}
|
||||
</section>);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default FileActions
|
||||
|
|
|
@ -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 {
|
|||
<div className="card__title-identity">
|
||||
<h5 title={title}><TruncatedText lines={1}>{title}</TruncatedText></h5>
|
||||
<div className="card__subtitle">
|
||||
{ !this.props.hidePrice ? <span style={{float: "right"}}><FilePrice uri={this.props.uri} /></span> : null}
|
||||
{ !this.props.hidePrice ? <span style={{float: "right"}}><FilePrice uri={lbryuri.normalize(this.props.uri)} /></span> : null}
|
||||
<UriIndicator uri={uri} metadata={metadata} contentType={this.props.contentType}
|
||||
hasSignature={this.props.hasSignature} signatureIsValid={this.props.signatureIsValid} />
|
||||
</div>
|
||||
|
|
22
ui/js/component/filePrice/index.js
Normal file
22
ui/js/component/filePrice/index.js
Normal file
|
@ -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)
|
21
ui/js/component/filePrice/view.jsx
Normal file
21
ui/js/component/filePrice/view.jsx
Normal file
|
@ -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 <span className={`credit-amount credit-amount--${look}`}>???</span>;
|
||||
}
|
||||
|
||||
return <CreditAmount label={false} amount={costInfo.cost} isEstimate={isEstimate} showFree={true} />
|
||||
}
|
||||
|
||||
export default FilePrice
|
|
@ -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*/
|
||||
|
|
|
@ -16,8 +16,6 @@ import {
|
|||
selectLoadingCurrentUri,
|
||||
selectCurrentUriFileReadyToPlay,
|
||||
selectCurrentUriIsPlaying,
|
||||
} from 'selectors/content'
|
||||
import {
|
||||
selectCurrentUriFileInfo,
|
||||
selectDownloadingCurrentUri,
|
||||
} from 'selectors/file_info'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 uri={this.props.uri} hasSignature={this.props.hasSignature} signatureIsValid={this.props.signatureIsValid} />;
|
||||
uriIndicator = <UriIndicator uri={uri} hasSignature={hasSignature} signatureIsValid={signatureIsValid} />
|
||||
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
|
@ -134,14 +134,14 @@ let FilePage = React.createClass({
|
|||
<div className="card__inner">
|
||||
<div className="card__title-identity">
|
||||
{this.state.isDownloaded === false
|
||||
? <span style={{float: "right"}}><FilePrice uri={this.props.uri} metadata={metadata} /></span>
|
||||
? <span style={{float: "right"}}><FilePrice uri={lbryuri.normalize(uri)} metadata={metadata} /></span>
|
||||
: null}
|
||||
<h1>{title}</h1>
|
||||
<div className="card__subtitle">
|
||||
{ this.props.channelUri ?
|
||||
<Link href={"?show=" + this.props.channelUri }>{uriIndicator}</Link> :
|
||||
uriIndicator}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<FileActions uri={this.props.uri} outpoint={this.props.outpoint} metadata={metadata} contentType={this.props.contentType} />
|
||||
</div>
|
||||
|
@ -289,3 +289,5 @@ let ShowPage = React.createClass({
|
|||
return <main className="main--single-column">{innerContent}</main>;
|
||||
}
|
||||
});
|
||||
|
||||
export default ShowPage;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue