Redux #115
23 changed files with 385 additions and 118 deletions
21
ui/js/actions/availability.js
Normal file
21
ui/js/actions/availability.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbry from 'lbry'
|
||||
|
||||
export function doFetchUriAvailability(uri) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.FETCH_AVAILABILITY_STARTED,
|
||||
data: { uri }
|
||||
})
|
||||
|
||||
lbry.get_availability({ uri }, (availability) => {
|
||||
dispatch({
|
||||
type: types.FETCH_AVAILABILITY_COMPLETED',
|
||||
data: {
|
||||
availability,
|
||||
uri,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbry from 'lbry'
|
||||
import lbryio from 'lbryio'
|
||||
import lbryuri from 'lbryuri'
|
||||
import {
|
||||
selectCurrentUri,
|
||||
} from 'selectors/app'
|
||||
|
@ -113,7 +114,9 @@ export function doFetchFeaturedContent() {
|
|||
})
|
||||
|
||||
Object.keys(Uris).forEach((category) => {
|
||||
Uris[category].forEach((uri) => dispatch(doResolveUri(uri)))
|
||||
Uris[category].forEach((uri) => {
|
||||
dispatch(doResolveUri(lbryuri.normalize(uri)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ export function doSearchContent(query) {
|
|||
contentName: result.name,
|
||||
claimId: result.channel_id || result.claim_id,
|
||||
})
|
||||
dispatch(doResolveUri(uri.split('://')[1]))
|
||||
dispatch(doResolveUri(uri))
|
||||
})
|
||||
|
||||
dispatch({
|
||||
|
|
21
ui/js/component/fileActions/index.js
Normal file
21
ui/js/component/fileActions/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect,
|
||||
} from 'react-redux'
|
||||
import {
|
||||
selectObscureNsfw,
|
||||
selectHidePrice,
|
||||
selectHasSignature,
|
||||
} from 'selectors/app'
|
||||
import FileActions from './view'
|
||||
|
||||
const select = (state) => ({
|
||||
obscureNsfw: selectObscureNsfw(state),
|
||||
hidePrice: selectHidePrice(state),
|
||||
hasSignature: selectHasSignature(state),
|
||||
})
|
||||
|
||||
const perform = {
|
||||
}
|
||||
|
||||
export default connect(select, perform)(FileActions)
|
|
@ -1,16 +1,16 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import lbryuri from '../lbryuri.js';
|
||||
import lbry from 'lbry';
|
||||
import lbryuri from 'lbryuri';
|
||||
import {Icon, FilePrice} from 'component/common';
|
||||
import {Modal} from 'component/modal';
|
||||
import {FormField} from 'component/form';
|
||||
import Link from 'component/link';
|
||||
import {Icon, FilePrice} from '../component/common.js';
|
||||
import Modal from './modal.js';
|
||||
import FormField from './form.js';
|
||||
import {ToolTip} from '../component/tooltip.js';
|
||||
import {DropDownMenu, DropDownMenuItem} from './menu.js';
|
||||
import {ToolTip} from 'component/tooltip';
|
||||
import {DropDownMenu, DropDownMenuItem} from 'component/menu';
|
||||
|
||||
const {shell} = require('electron');
|
||||
|
||||
let FileActionsRow = React.createClass({
|
||||
const FileActionsRow = React.createClass({
|
||||
_isMounted: false,
|
||||
_fileInfoSubscribeId: null,
|
||||
|
||||
|
@ -192,7 +192,7 @@ let FileActionsRow = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
export let FileActions = React.createClass({
|
||||
const FileActions = React.createClass({
|
||||
_isMounted: false,
|
||||
_fileInfoSubscribeId: null,
|
||||
|
||||
|
@ -268,3 +268,5 @@ export let FileActions = React.createClass({
|
|||
</section>);
|
||||
}
|
||||
});
|
||||
|
||||
export default FileActions
|
|
@ -5,13 +5,40 @@ import {
|
|||
import {
|
||||
doNavigate,
|
||||
} from 'actions/app'
|
||||
import {
|
||||
selectHidePrice,
|
||||
selectObscureNsfw,
|
||||
} from 'selectors/app'
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectSourceForUri,
|
||||
makeSelectMetadataForUri,
|
||||
} from 'selectors/claims'
|
||||
import {
|
||||
makeSelectFileInfoForUri,
|
||||
} from 'selectors/file_info'
|
||||
import FileCardStream from './view'
|
||||
|
||||
const select = (state) => ({
|
||||
})
|
||||
const makeSelect = () => {
|
||||
const selectClaimForUri = makeSelectClaimForUri()
|
||||
const selectFileInfoForUri = makeSelectFileInfoForUri()
|
||||
const selectMetadataForUri = makeSelectMetadataForUri()
|
||||
const selectSourceForUri = makeSelectSourceForUri()
|
||||
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),
|
||||
})
|
||||
|
||||
return select
|
||||
}
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
navigate: (path) => dispatch(doNavigate(path)),
|
||||
})
|
||||
|
||||
export default connect(select, perform)(FileCardStream)
|
||||
export default connect(makeSelect, perform)(FileCardStream)
|
||||
|
|
|
@ -2,70 +2,63 @@ import React from 'react';
|
|||
import lbry from 'lbry.js';
|
||||
import lbryuri from 'lbryuri.js';
|
||||
import Link from 'component/link';
|
||||
import {FileActions} from 'component/file-actions.js';
|
||||
import {Thumbnail, TruncatedText, FilePrice} from 'component/common.js';
|
||||
import UriIndicator from 'component/channel-indicator.js';
|
||||
import {Thumbnail, TruncatedText, FilePrice} from 'component/common';
|
||||
import UriIndicator from 'component/channel-indicator';
|
||||
|
||||
const FileCardStream = React.createClass({
|
||||
_fileInfoSubscribeId: null,
|
||||
_isMounted: null,
|
||||
_metadata: null,
|
||||
|
||||
|
||||
propTypes: {
|
||||
uri: React.PropTypes.string,
|
||||
claimInfo: React.PropTypes.object,
|
||||
outpoint: React.PropTypes.string,
|
||||
hideOnRemove: React.PropTypes.bool,
|
||||
hidePrice: React.PropTypes.bool,
|
||||
obscureNsfw: React.PropTypes.bool
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
class FileCardStream extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._fileInfoSubscribeId = null
|
||||
this._isMounted = null
|
||||
this._metadata = null
|
||||
this.state = {
|
||||
showNsfwHelp: false,
|
||||
isHidden: false,
|
||||
}
|
||||
},
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
obscureNsfw: !lbry.getClientSetting('showNsfw'),
|
||||
hidePrice: false,
|
||||
hasSignature: false,
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
if (this.props.hideOnRemove) {
|
||||
this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
|
||||
}
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._fileInfoSubscribeId) {
|
||||
lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
|
||||
}
|
||||
},
|
||||
onFileInfoUpdate: function(fileInfo) {
|
||||
}
|
||||
|
||||
onFileInfoUpdate(fileInfo) {
|
||||
if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
|
||||
this.setState({
|
||||
isHidden: true
|
||||
});
|
||||
}
|
||||
},
|
||||
handleMouseOver: function() {
|
||||
}
|
||||
|
||||
handleMouseOver() {
|
||||
this.setState({
|
||||
hovered: true,
|
||||
});
|
||||
},
|
||||
handleMouseOut: function() {
|
||||
}
|
||||
|
||||
handleMouseOut() {
|
||||
this.setState({
|
||||
hovered: false,
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this.props.metadata) {
|
||||
return null
|
||||
}
|
||||
|
||||
const uri = lbryuri.normalize(this.props.uri);
|
||||
const metadata = this.props.metadata;
|
||||
const isConfirmed = !!metadata;
|
||||
|
@ -73,13 +66,13 @@ const FileCardStream = React.createClass({
|
|||
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
|
||||
const primaryUrl = 'show=' + uri;
|
||||
return (
|
||||
<section className={ 'card card--small card--link ' + (obscureNsfw ? 'card--obscured ' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
|
||||
<section className={ 'card card--small card--link ' + (obscureNsfw ? 'card--obscured ' : '') } onMouseEnter={this.handleMouseOver.bind(this)} onMouseLeave={this.handleMouseOut.bind(this)}>
|
||||
<div className="card__inner">
|
||||
<a href="#" onClick={() => this.props.navigate(primaryUrl)} className="card__link">
|
||||
<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} metadata={metadata} /></span> : null}
|
||||
{ !this.props.hidePrice ? <span style={{float: "right"}}><FilePrice uri={this.props.uri} /></span> : null}
|
||||
<UriIndicator uri={uri} metadata={metadata} contentType={this.props.contentType}
|
||||
hasSignature={this.props.hasSignature} signatureIsValid={this.props.signatureIsValid} />
|
||||
</div>
|
||||
|
@ -105,6 +98,6 @@ const FileCardStream = React.createClass({
|
|||
</section>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default FileCardStream
|
||||
|
|
|
@ -79,9 +79,7 @@ const FileList = React.createClass({
|
|||
|
||||
const uri = lbryuri.build({contentName: name, channelName: channel_name});
|
||||
seenUris[name] = true;
|
||||
content.push(<FileTileStream key={outpoint} outpoint={outpoint} uri={uri} hideOnRemove={true}
|
||||
hidePrice={this.props.hidePrices} metadata={streamMetadata} contentType={mime_type}
|
||||
hasSignature={has_signature} signatureIsValid={signature_is_valid} />);
|
||||
content.push(<FileTileStream key={outpoint} uri={uri} hideOnRemove={true} />)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -3,15 +3,25 @@ import {
|
|||
connect
|
||||
} from 'react-redux'
|
||||
import {
|
||||
selectClaimsByUri,
|
||||
makeSelectClaimForUri,
|
||||
} from 'selectors/claims'
|
||||
import {
|
||||
makeSelectFileInfoForUri,
|
||||
} from 'selectors/file_info'
|
||||
import FileTile from './view'
|
||||
|
||||
const select = (state) => ({
|
||||
claims: (uri) => selectClaimsByUri(state)[uri],
|
||||
})
|
||||
const makeSelect = () => {
|
||||
const selectClaimForUri = makeSelectClaimForUri()
|
||||
const selectFileInfoForUri = makeSelectFileInfoForUri()
|
||||
const select = (state, props) => ({
|
||||
claim: selectClaimForUri(state, props),
|
||||
fileInfo: selectFileInfoForUri(state, props),
|
||||
})
|
||||
|
||||
return select
|
||||
}
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
})
|
||||
|
||||
export default connect(select, perform)(FileTile)
|
||||
export default connect(makeSelect, perform)(FileTile)
|
||||
|
|
|
@ -10,11 +10,11 @@ class FileTile extends React.Component {
|
|||
render() {
|
||||
const {
|
||||
displayStyle,
|
||||
uri
|
||||
uri,
|
||||
claim,
|
||||
} = this.props
|
||||
const claimInfo = this.props.claims(uri)
|
||||
|
||||
if(!claimInfo) {
|
||||
if(!claim) {
|
||||
if (displayStyle == 'card') {
|
||||
return <FileCardStream uri={uri} />
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ class FileTile extends React.Component {
|
|||
}
|
||||
|
||||
return displayStyle == 'card' ?
|
||||
<FileCardStream uri={uri} />
|
||||
<FileCardStream uri={uri} />
|
||||
:
|
||||
<FileTileStream uri={uri} key={uri} />
|
||||
<FileTileStream uri={uri} key={uri} />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,46 @@ import {
|
|||
import {
|
||||
doNavigate,
|
||||
} from 'actions/app'
|
||||
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 FileTileStream from './view'
|
||||
|
||||
const select = (state) => ({
|
||||
})
|
||||
const makeSelect = () => {
|
||||
const selectClaimForUri = makeSelectClaimForUri()
|
||||
const selectFileInfoForUri = makeSelectFileInfoForUri()
|
||||
const selectFetchingAvailabilityForUri = makeSelectFetchingAvailabilityForUri()
|
||||
const selectAvailabilityForUri = makeSelectAvailabilityForUri()
|
||||
const selectMetadataForUri = makeSelectMetadataForUri()
|
||||
const selectSourceForUri = makeSelectSourceForUri()
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: selectClaimForUri(state, props),
|
||||
fileInfo: selectFileInfoForUri(state, props),
|
||||
fetchingAvailability: selectFetchingAvailabilityForUri(state, props),
|
||||
selectAvailabilityForUri: selectAvailabilityForUri(state, props),
|
||||
obscureNswf: selectObscureNsfw(state),
|
||||
metadata: selectMetadataForUri(state, props),
|
||||
source: selectSourceForUri(state, props),
|
||||
})
|
||||
|
||||
return select
|
||||
}
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
navigate: (path) => dispatch(doNavigate(path))
|
||||
})
|
||||
|
||||
export default connect(select, perform)(FileTileStream)
|
||||
export default connect(makeSelect, perform)(FileTileStream)
|
||||
|
|
|
@ -2,86 +2,76 @@ import React from 'react';
|
|||
import lbry from 'lbry.js';
|
||||
import lbryuri from 'lbryuri.js';
|
||||
import Link from 'component/link';
|
||||
import {
|
||||
FileActions
|
||||
} from 'component/file-actions.js';
|
||||
import FileActions from 'component/fileActions';
|
||||
import {Thumbnail, TruncatedText, FilePrice} from 'component/common.js';
|
||||
import UriIndicator from 'component/channel-indicator.js';
|
||||
|
||||
/*should be merged into FileTile once FileTile is refactored to take a single id*/
|
||||
const FileTileStream = React.createClass({
|
||||
_fileInfoSubscribeId: null,
|
||||
_isMounted: null,
|
||||
|
||||
propTypes: {
|
||||
uri: React.PropTypes.string,
|
||||
metadata: React.PropTypes.object,
|
||||
contentType: React.PropTypes.string.isRequired,
|
||||
outpoint: React.PropTypes.string,
|
||||
hasSignature: React.PropTypes.bool,
|
||||
signatureIsValid: React.PropTypes.bool,
|
||||
hideOnRemove: React.PropTypes.bool,
|
||||
hidePrice: React.PropTypes.bool,
|
||||
obscureNsfw: React.PropTypes.bool
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
class FileTileStream extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._fileInfoSubscribeId = null
|
||||
this._isMounted = null
|
||||
this.state = {
|
||||
showNsfwHelp: false,
|
||||
isHidden: false,
|
||||
}
|
||||
},
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
obscureNsfw: !lbry.getClientSetting('showNsfw'),
|
||||
hidePrice: false,
|
||||
hasSignature: false,
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
if (this.props.hideOnRemove) {
|
||||
this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
|
||||
}
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._fileInfoSubscribeId) {
|
||||
lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
|
||||
}
|
||||
},
|
||||
onFileInfoUpdate: function(fileInfo) {
|
||||
}
|
||||
|
||||
onFileInfoUpdate(fileInfo) {
|
||||
if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
|
||||
this.setState({
|
||||
isHidden: true
|
||||
});
|
||||
}
|
||||
},
|
||||
handleMouseOver: function() {
|
||||
}
|
||||
|
||||
handleMouseOver() {
|
||||
if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) {
|
||||
this.setState({
|
||||
showNsfwHelp: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
handleMouseOut: function() {
|
||||
}
|
||||
|
||||
handleMouseOut() {
|
||||
if (this.state.showNsfwHelp) {
|
||||
this.setState({
|
||||
showNsfwHelp: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
metadata,
|
||||
navigate,
|
||||
} = this.props
|
||||
|
||||
const uri = lbryuri.normalize(this.props.uri);
|
||||
const metadata = this.props.metadata;
|
||||
const isConfirmed = !!metadata;
|
||||
const title = isConfirmed ? metadata.title : uri;
|
||||
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
|
||||
const { navigate } = this.props
|
||||
|
||||
return (
|
||||
<section className={ 'file-tile card ' + (obscureNsfw ? 'card--obscured ' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
|
||||
<section className={ 'file-tile card ' + (obscureNsfw ? 'card--obscured ' : '') } onMouseEnter={this.handleMouseOver.bind(this)} onMouseLeave={this.handleMouseOut.bind(this)}>
|
||||
<div className={"row-fluid card__inner file-tile__row"}>
|
||||
<div className="span3 file-tile__thumbnail-container">
|
||||
<a href="#" onClick={() => navigate(`show=${uri}`)}><Thumbnail className="file-tile__thumbnail" {... metadata && metadata.thumbnail ? {src: metadata.thumbnail} : {}} alt={'Photo for ' + this.props.uri} /></a>
|
||||
|
@ -101,7 +91,6 @@ const FileTileStream = React.createClass({
|
|||
</h3>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<FileActions uri={this.props.uri} outpoint={this.props.outpoint} metadata={metadata} contentType={this.props.contentType} />
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p className="file-tile__description">
|
||||
|
@ -125,6 +114,6 @@ const FileTileStream = React.createClass({
|
|||
</section>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default FileTileStream
|
||||
|
|
|
@ -54,6 +54,8 @@ export const DOWNLOADING_STARTED = 'DOWNLOADING_STARTED'
|
|||
export const DOWNLOADING_PROGRESSED = 'DOWNLOADING_PROGRESSED'
|
||||
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'
|
||||
|
||||
// Search
|
||||
export const SEARCH_STARTED = 'SEARCH_STARTED'
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
FilePrice,
|
||||
BusyMessage
|
||||
} from 'component/common.js';
|
||||
import {FileActions} from 'component/file-actions.js';
|
||||
import FileActions from 'component/fileActions';
|
||||
import Link from 'component/link';
|
||||
import UriIndicator from 'component/channel-indicator.js';
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbry from 'lbry'
|
||||
|
||||
const reducers = {}
|
||||
const defaultState = {
|
||||
|
@ -9,6 +10,9 @@ const defaultState = {
|
|||
upgradeSkipped: sessionStorage.getItem('upgradeSkipped'),
|
||||
daemonReady: false,
|
||||
platform: window.navigator.platform,
|
||||
obscureNsfw: !lbry.getClientSetting('showNsfw'),
|
||||
hidePrice: false,
|
||||
hasSignature: false,
|
||||
}
|
||||
|
||||
reducers[types.NAVIGATE] = function(state, action) {
|
||||
|
|
45
ui/js/reducers/availability.js
Normal file
45
ui/js/reducers/availability.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import * as types from 'constants/action_types'
|
||||
|
||||
const reducers = {}
|
||||
const defaultState = {
|
||||
}
|
||||
|
||||
reducers[types.FETCH_AVAILABILITY_STARTED] = function(state, action) {
|
||||
const {
|
||||
uri,
|
||||
} = action.data
|
||||
const newFetching = Object.assign({}, state.fetching)
|
||||
const newByUri = Object.assign({}, newFetching.byUri)
|
||||
|
||||
newByUri[uri] = true
|
||||
newFetching.byUri = newByUri
|
||||
|
||||
return Object.assign({}, state, {
|
||||
fetching: newFetching,
|
||||
})
|
||||
}
|
||||
|
||||
reducers[types.FETCH_AVAILABILITY_COMPLETED] = function(state, action) {
|
||||
const {
|
||||
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
|
||||
newAvailabilityByUri[uri] = availability
|
||||
|
||||
return Object.assign({}, state, {
|
||||
fetching: newFetching,
|
||||
byUri: newAvailabilityByUri
|
||||
})
|
||||
}
|
||||
|
||||
export default function reducer(state = defaultState, action) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
return state;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbryuri from 'lbryuri'
|
||||
|
||||
const reducers = {}
|
||||
const defaultState = {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbryuri from 'lbryuri'
|
||||
|
||||
const reducers = {}
|
||||
const defaultState = {
|
||||
|
@ -18,10 +19,11 @@ reducers[types.SEARCH_STARTED] = function(state, action) {
|
|||
reducers[types.SEARCH_COMPLETED] = function(state, action) {
|
||||
const {
|
||||
query,
|
||||
results,
|
||||
} = action.data
|
||||
const oldResults = Object.assign({}, state.results)
|
||||
const newByQuery = Object.assign({}, oldResults.byQuery)
|
||||
newByQuery[query] = action.data.results
|
||||
newByQuery[query] = results
|
||||
const newResults = Object.assign({}, oldResults, {
|
||||
byQuery: newByQuery
|
||||
})
|
||||
|
|
|
@ -19,7 +19,13 @@ export const selectCurrentPage = createSelector(
|
|||
|
||||
export const selectCurrentUri = createSelector(
|
||||
selectCurrentPath,
|
||||
(path) => path.split('://')[1]
|
||||
(path) => {
|
||||
if (path.match(/=/)) {
|
||||
return path.split('=')[1]
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const selectPlatform = createSelector(
|
||||
|
@ -145,3 +151,18 @@ export const selectDaemonReady = createSelector(
|
|||
_selectState,
|
||||
(state) => state.daemonReady
|
||||
)
|
||||
|
||||
export const selectObscureNsfw = createSelector(
|
||||
_selectState,
|
||||
(state) => !!state.obscureNsfw
|
||||
)
|
||||
|
||||
export const selectHidePrice = createSelector(
|
||||
_selectState,
|
||||
(state) => !!state.hidePrice
|
||||
)
|
||||
|
||||
export const selectHasSignature = createSelector(
|
||||
_selectState,
|
||||
(state) => !!state.hasSignature
|
||||
)
|
||||
|
|
42
ui/js/selectors/availability.js
Normal file
42
ui/js/selectors/availability.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import {
|
||||
createSelector,
|
||||
} from 'reselect'
|
||||
|
||||
const _selectState = state => state.availability
|
||||
|
||||
export const selectAvailabilityByUri = createSelector(
|
||||
_selectState,
|
||||
(state) => state.byUri || {}
|
||||
)
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
export const makeSelectFetchingAvailabilityForUri = () => {
|
||||
return createSelector(
|
||||
selectFetchingAvailabilityForUri,
|
||||
(fetching) => fetching
|
||||
)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
createSelector,
|
||||
} from 'reselect'
|
||||
import lbryuri from 'lbryuri'
|
||||
import {
|
||||
selectCurrentUri,
|
||||
} from 'selectors/app'
|
||||
|
@ -22,3 +23,43 @@ export const selectCurrentUriClaimOutpoint = createSelector(
|
|||
selectCurrentUriClaim,
|
||||
(claim) => `${claim.txid}:${claim.nout}`
|
||||
)
|
||||
|
||||
const selectClaimForUri = (state, props) => {
|
||||
const uri = lbryuri.normalize(props.uri)
|
||||
return selectClaimsByUri(state)[uri]
|
||||
}
|
||||
|
||||
export const makeSelectClaimForUri = () => {
|
||||
return createSelector(
|
||||
selectClaimForUri,
|
||||
(claim) => claim
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
export const makeSelectMetadataForUri = () => {
|
||||
return createSelector(
|
||||
selectMetadataForUri,
|
||||
(metadata) => metadata
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
export const makeSelectSourceForUri = () => {
|
||||
return createSelector(
|
||||
selectSourceForUri,
|
||||
(source) => source
|
||||
)
|
||||
}
|
||||
|
|
|
@ -72,3 +72,13 @@ export const shouldFetchCurrentUriFileInfo = createSelector(
|
|||
}
|
||||
)
|
||||
|
||||
const selectFileInfoForUri = (state, props) => {
|
||||
return selectAllFileInfoByUri(state)[props.uri]
|
||||
}
|
||||
|
||||
export const makeSelectFileInfoForUri = () => {
|
||||
return createSelector(
|
||||
selectFileInfoForUri,
|
||||
(fileInfo) => fileInfo
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
createLogger
|
||||
} 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';
|
||||
|
@ -47,6 +48,7 @@ function enableBatching(reducer) {
|
|||
|
||||
const reducers = redux.combineReducers({
|
||||
app: appReducer,
|
||||
availability: availabilityReducer,
|
||||
certificates: certificatesReducer,
|
||||
claims: claimsReducer,
|
||||
fileInfo: fileInfoReducer,
|
||||
|
|
Loading…
Reference in a new issue