From 393aa9129c5e676e4a1ab64ccc7f7fa67caa22fd Mon Sep 17 00:00:00 2001
From: 6ea86b96 <6ea86b96@gmail.com>
Date: Sun, 23 Apr 2017 21:01:00 +0700
Subject: [PATCH] Featured content
---
ui/js/actions/content.js | 27 +++
ui/js/component/fileCardStream/index.js | 7 +
ui/js/component/fileCardStream/view.jsx | 110 +++++++++
ui/js/component/fileTile/index.js | 4 +
ui/js/component/fileTile/view.jsx | 295 ++----------------------
ui/js/constants/action_types.js | 2 +
ui/js/page/discover/view.jsx | 1 +
ui/js/reducers/content.js | 42 ++++
ui/js/selectors/content.js | 5 +
9 files changed, 219 insertions(+), 274 deletions(-)
create mode 100644 ui/js/component/fileCardStream/index.js
create mode 100644 ui/js/component/fileCardStream/view.jsx
diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js
index a4e582ffe..08411bab3 100644
--- a/ui/js/actions/content.js
+++ b/ui/js/actions/content.js
@@ -2,6 +2,29 @@ import * as types from 'constants/action_types'
import lbry from 'lbry'
import lbryio from 'lbryio';
+export function doResolveUri(dispatch, uri) {
+ dispatch({
+ type: types.RESOLVE_URI_STARTED,
+ data: { uri }
+ })
+
+ lbry.resolve({uri: uri}).then((resolutionInfo) => {
+ const {
+ claim,
+ certificate,
+ } = resolutionInfo
+
+ dispatch({
+ type: types.RESOLVE_URI_COMPLETED,
+ data: {
+ uri,
+ claim,
+ certificate,
+ }
+ })
+ })
+}
+
export function doFetchFeaturedContent() {
return function(dispatch, getState) {
const state = getState()
@@ -18,6 +41,10 @@ export function doFetchFeaturedContent() {
uris: Uris,
}
})
+
+ Object.keys(Uris).forEach((category) => {
+ Uris[category].forEach((uri) => doResolveUri(dispatch, uri))
+ })
}
const failure = () => {
diff --git a/ui/js/component/fileCardStream/index.js b/ui/js/component/fileCardStream/index.js
new file mode 100644
index 000000000..ec4800f32
--- /dev/null
+++ b/ui/js/component/fileCardStream/index.js
@@ -0,0 +1,7 @@
+import React from 'react'
+import {
+ connect
+} from 'react-redux'
+import FileCardStream from './view'
+
+export default connect()(FileCardStream)
diff --git a/ui/js/component/fileCardStream/view.jsx b/ui/js/component/fileCardStream/view.jsx
new file mode 100644
index 000000000..1dca3d48f
--- /dev/null
+++ b/ui/js/component/fileCardStream/view.jsx
@@ -0,0 +1,110 @@
+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';
+
+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 {
+ showNsfwHelp: false,
+ isHidden: false,
+ }
+ },
+ getDefaultProps: function() {
+ return {
+ obscureNsfw: !lbry.getClientSetting('showNsfw'),
+ hidePrice: false,
+ hasSignature: false,
+ }
+ },
+ componentDidMount: function() {
+ this._isMounted = true;
+ if (this.props.hideOnRemove) {
+ this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
+ }
+ },
+ componentWillUnmount: function() {
+ if (this._fileInfoSubscribeId) {
+ lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
+ }
+ },
+ onFileInfoUpdate: function(fileInfo) {
+ if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
+ this.setState({
+ isHidden: true
+ });
+ }
+ },
+ handleMouseOver: function() {
+ this.setState({
+ hovered: true,
+ });
+ },
+ handleMouseOut: function() {
+ this.setState({
+ hovered: false,
+ });
+ },
+ render: function() {
+ if (this.state.isHidden) {
+ return null;
+ }
+
+ 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 primaryUrl = '?show=' + uri;
+ return (
+
+ );
+ }
+});
+
+export default FileCardStream
diff --git a/ui/js/component/fileTile/index.js b/ui/js/component/fileTile/index.js
index b410bc9c2..e24dade66 100644
--- a/ui/js/component/fileTile/index.js
+++ b/ui/js/component/fileTile/index.js
@@ -2,9 +2,13 @@ import React from 'react'
import {
connect
} from 'react-redux'
+import {
+ selectResolvedUris,
+} from 'selectors/content'
import FileTile from './view'
const select = (state) => ({
+ resolvedUris: selectResolvedUris(state),
})
const perform = (dispatch) => ({
diff --git a/ui/js/component/fileTile/view.jsx b/ui/js/component/fileTile/view.jsx
index b85b0ec6a..b80616dcc 100644
--- a/ui/js/component/fileTile/view.jsx
+++ b/ui/js/component/fileTile/view.jsx
@@ -2,283 +2,30 @@ 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 FileCardStream from 'component/fileCardStream'
+import FileTileStream from 'component/fileTileStream'
+import FileActions from 'component/fileActions';
-/*should be merged into FileTile once FileTile is refactored to take a single id*/
-export let FileTileStream = React.createClass({
- _fileInfoSubscribeId: null,
- _isMounted: null,
+class FileTile extends React.Component {
+ render() {
+ const {
+ displayStyle,
+ uri,
+ claim,
+ } = this.props
- 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 {
- showNsfwHelp: false,
- isHidden: false,
- }
- },
- getDefaultProps: function() {
- return {
- obscureNsfw: !lbry.getClientSetting('showNsfw'),
- hidePrice: false,
- hasSignature: false,
- }
- },
- componentDidMount: function() {
- this._isMounted = true;
- if (this.props.hideOnRemove) {
- this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
- }
- },
- componentWillUnmount: function() {
- if (this._fileInfoSubscribeId) {
- lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
- }
- },
- onFileInfoUpdate: function(fileInfo) {
- if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
- this.setState({
- isHidden: true
- });
- }
- },
- handleMouseOver: function() {
- if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) {
- this.setState({
- showNsfwHelp: true,
- });
- }
- },
- handleMouseOut: function() {
- if (this.state.showNsfwHelp) {
- this.setState({
- showNsfwHelp: false,
- });
- }
- },
- render: function() {
- if (this.state.isHidden) {
- return null;
- }
-
- 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 primaryUrl = "?show=" + uri;
- return (
-
- );
- }
-});
-
-export let 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 {
- showNsfwHelp: false,
- isHidden: false,
- }
- },
- getDefaultProps: function() {
- return {
- obscureNsfw: !lbry.getClientSetting('showNsfw'),
- hidePrice: false,
- hasSignature: false,
- }
- },
- componentDidMount: function() {
- this._isMounted = true;
- if (this.props.hideOnRemove) {
- this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.outpoint, this.onFileInfoUpdate);
- }
- },
- componentWillUnmount: function() {
- if (this._fileInfoSubscribeId) {
- lbry.fileInfoUnsubscribe(this.props.outpoint, this._fileInfoSubscribeId);
- }
- },
- onFileInfoUpdate: function(fileInfo) {
- if (!fileInfo && this._isMounted && this.props.hideOnRemove) {
- this.setState({
- isHidden: true
- });
- }
- },
- handleMouseOver: function() {
- this.setState({
- hovered: true,
- });
- },
- handleMouseOut: function() {
- this.setState({
- hovered: false,
- });
- },
- render: function() {
- if (this.state.isHidden) {
- return null;
- }
-
- 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 primaryUrl = '?show=' + uri;
- return (
-
- );
- }
-});
-
-let FileTile = React.createClass({
- _isMounted: false,
- _isResolvePending: false,
-
- propTypes: {
- uri: React.PropTypes.string.isRequired,
- },
-
- getInitialState: function() {
- return {
- outpoint: null,
- claimInfo: null
- }
- },
- resolve: function(uri) {
- this._isResolvePending = true;
- lbry.resolve({uri: uri}).then((resolutionInfo) => {
- this._isResolvePending = false;
- if (this._isMounted && resolutionInfo && resolutionInfo.claim && resolutionInfo.claim.value &&
- resolutionInfo.claim.value.stream && resolutionInfo.claim.value.stream.metadata) {
- // In case of a failed lookup, metadata will be null, in which case the component will never display
- this.setState({
- claimInfo: resolutionInfo.claim,
- });
+ if(!claim) {
+ if (displayStyle == 'card') {
+ return
}
- });
- },
- componentWillReceiveProps: function(nextProps) {
- if (nextProps.uri != this.props.uri) {
- this.setState(this.getInitialState());
- this.resolve(nextProps.uri);
- }
- },
- componentDidMount: function() {
- this._isMounted = true;
- this.resolve(this.props.uri);
- },
- componentWillUnmount: function() {
- this._isMounted = false;
- },
- render: function() {
- if (!this.state.claimInfo) {
- if (this.props.displayStyle == 'card') {
- return
- }
- if (this.props.showEmpty)
- {
- return this._isResolvePending ?
- :
-
{lbryuri.normalize(this.props.uri)} is unclaimed.
;
- }
- return null;
+ return null
}
- const {txid, nout, has_signature, signature_is_valid,
- value: {stream: {metadata, source: {contentType}}}} = this.state.claimInfo;
-
- return this.props.displayStyle == 'card' ?
- :
- ;
+ return displayStyle == 'card' ?
+
+ :
+
}
-});
\ No newline at end of file
+}
+
+export default FileTile
\ No newline at end of file
diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js
index e0fae5d24..0172662f6 100644
--- a/ui/js/constants/action_types.js
+++ b/ui/js/constants/action_types.js
@@ -37,3 +37,5 @@ export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED'
// Content
export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED'
export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED'
+export const RESOLVE_URI_STARTED = 'RESOLVE_URI_STARTED'
+export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED'
diff --git a/ui/js/page/discover/view.jsx b/ui/js/page/discover/view.jsx
index a8ad512b7..30d434ef3 100644
--- a/ui/js/page/discover/view.jsx
+++ b/ui/js/page/discover/view.jsx
@@ -11,6 +11,7 @@ const communityCategoryToolTipText = ('Community Content is a public space where
const FeaturedCategory = (props) => {
const {
category,
+ resolvedUris,
names,
} = props
diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js
index aefdb11c7..5b9cc2e04 100644
--- a/ui/js/reducers/content.js
+++ b/ui/js/reducers/content.js
@@ -24,6 +24,48 @@ reducers[types.FETCH_FEATURED_CONTENT_COMPLETED] = function(state, action) {
})
}
+reducers[types.RESOLVE_URI_STARTED] = function(state, action) {
+ const {
+ uri
+ } = action.data
+
+ const oldResolving = state.resolvingUris || []
+ const newResolving = Object.assign([], oldResolving)
+ if (newResolving.indexOf(uri) == -1) newResolving.push(uri)
+
+ return Object.assign({}, state, {
+ resolvingUris: newResolving
+ })
+}
+
+reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) {
+ const {
+ uri,
+ claim,
+ certificate,
+ } = action.data
+ const resolvedUris = Object.assign({}, state.resolvedUris)
+ const resolvingUris = state.resolvingUris
+ const index = state.resolvingUris.indexOf(uri)
+ const newResolvingUris = [
+ ...resolvingUris.slice(0, index),
+ ...resolvingUris.slice(index + 1)
+ ]
+
+ resolvedUris[uri] = {
+ claim: claim,
+ certificate: certificate,
+ }
+
+
+ const newState = Object.assign({}, state, {
+ resolvedUris: resolvedUris,
+ resolvingUris: newResolvingUris,
+ })
+
+ return Object.assign({}, state, newState)
+}
+
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js
index 7e5905ecb..e2222cb91 100644
--- a/ui/js/selectors/content.js
+++ b/ui/js/selectors/content.js
@@ -35,3 +35,8 @@ export const shouldFetchFeaturedContent = createSelector(
return true
}
)
+
+export const selectResolvedUris = createSelector(
+ _selectState,
+ (state) => state.resolvedUris || {}
+)