diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js index 08411bab3..8b5499dc5 100644 --- a/ui/js/actions/content.js +++ b/ui/js/actions/content.js @@ -25,6 +25,52 @@ export function doResolveUri(dispatch, uri) { }) } +export function doFetchDownloadedContent() { + return function(dispatch, getState) { + const state = getState() + + dispatch({ + type: types.FETCH_DOWNLOADED_CONTENT_STARTED, + }) + + lbry.claim_list_mine().then((myClaimInfos) => { + lbry.file_list().then((fileInfos) => { + const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); + + dispatch({ + type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, + data: { + fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), + } + }) + }); + }); + } +} + +export function doFetchPublishedContent() { + return function(dispatch, getState) { + const state = getState() + + dispatch({ + type: types.FETCH_PUBLISHED_CONTENT_STARTED, + }) + + lbry.claim_list_mine().then((claimInfos) => { + lbry.file_list().then((fileInfos) => { + const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout) + + dispatch({ + type: types.FETCH_PUBLISHED_CONTENT_COMPLETED, + data: { + fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), + } + }) + }) + }) + } +} + export function doFetchFeaturedContent() { return function(dispatch, getState) { const state = getState() diff --git a/ui/js/component/fileList/index.js b/ui/js/component/fileList/index.js new file mode 100644 index 000000000..0a6c65c70 --- /dev/null +++ b/ui/js/component/fileList/index.js @@ -0,0 +1,7 @@ +import React from 'react' +import { + connect +} from 'react-redux' +import FileList from './view' + +export default connect()(FileList) diff --git a/ui/js/component/fileList/view.jsx b/ui/js/component/fileList/view.jsx new file mode 100644 index 000000000..7d1cc9409 --- /dev/null +++ b/ui/js/component/fileList/view.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import lbry from 'lbry.js'; +import lbryuri from 'lbryuri.js'; +import Link from 'component/link'; +import {FormField} from 'component/form.js'; +import FileTileStream from 'component/fileTile'; +import rewards from 'rewards.js'; +import lbryio from 'lbryio.js'; +import {BusyMessage, Thumbnail} from 'component/common.js'; + +const FileList = React.createClass({ + _sortFunctions: { + date: function(fileInfos) { + return fileInfos.slice().reverse(); + }, + title: function(fileInfos) { + return fileInfos.slice().sort(function(fileInfo1, fileInfo2) { + const title1 = fileInfo1.metadata ? fileInfo1.metadata.title.toLowerCase() : fileInfo1.name; + const title2 = fileInfo2.metadata ? fileInfo2.metadata.title.toLowerCase() : fileInfo2.name; + if (title1 < title2) { + return -1; + } else if (title1 > title2) { + return 1; + } else { + return 0; + } + }); + }, + filename: function(fileInfos) { + return fileInfos.slice().sort(function({file_name: fileName1}, {file_name: fileName2}) { + const fileName1Lower = fileName1.toLowerCase(); + const fileName2Lower = fileName2.toLowerCase(); + if (fileName1Lower < fileName2Lower) { + return -1; + } else if (fileName2Lower > fileName1Lower) { + return 1; + } else { + return 0; + } + }); + }, + }, + propTypes: { + fileInfos: React.PropTypes.array.isRequired, + hidePrices: React.PropTypes.bool, + }, + getDefaultProps: function() { + return { + hidePrices: false, + }; + }, + getInitialState: function() { + return { + sortBy: 'date', + }; + }, + handleSortChanged: function(event) { + this.setState({ + sortBy: event.target.value, + }); + }, + render: function() { + var content = [], + seenUris = {}; + + const fileInfosSorted = this._sortFunctions[this.state.sortBy](this.props.fileInfos); + for (let {outpoint, name, channel_name, metadata, mime_type, claim_id, has_signature, signature_is_valid} of fileInfosSorted) { + if (seenUris[name] || !claim_id) { + continue; + } + + let streamMetadata; + if (metadata) { + streamMetadata = metadata.stream.metadata; + } else { + streamMetadata = null; + } + + + const uri = lbryuri.build({contentName: name, channelName: channel_name}); + seenUris[name] = true; + content.push(); + } + + return ( +
+ + Sort by { ' ' } + + + + + + + {content} +
+ ); + } +}); + +export default FileList diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx index 9f553c9b7..940c41646 100644 --- a/ui/js/component/router/view.jsx +++ b/ui/js/component/router/view.jsx @@ -9,10 +9,8 @@ import PublishPage from 'page/publish.js'; import DiscoverPage from 'page/discover'; import SplashScreen from 'component/splash.js'; import DeveloperPage from 'page/developer.js'; -import { - FileListDownloaded, - FileListPublished -} from 'page/file-list.js'; +import FileListDownloaded from 'page/fileListDownloaded' +import FileListPublished from 'page/fileListPublished' const route = (page, routesMap) => { const component = routesMap[page] diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index 0172662f6..776da726b 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -39,3 +39,7 @@ export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED' export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED' export const RESOLVE_URI_STARTED = 'RESOLVE_URI_STARTED' export const RESOLVE_URI_COMPLETED = 'RESOLVE_URI_COMPLETED' +export const FETCH_DOWNLOADED_CONTENT_STARTED = 'FETCH_DOWNLOADED_CONTENT_STARTED' +export const FETCH_DOWNLOADED_CONTENT_COMPLETED = 'FETCH_DOWNLOADED_CONTENT_COMPLETED' +export const FETCH_PUBLISHED_CONTENT_STARTED = 'FETCH_PUBLISHED_CONTENT_STARTED' +export const FETCH_PUBLISHED_CONTENT_COMPLETED = 'FETCH_PUBLISHED_CONTENT_COMPLETED' diff --git a/ui/js/page/file-list.js b/ui/js/page/file-list.js deleted file mode 100644 index 7d609b3f4..000000000 --- a/ui/js/page/file-list.js +++ /dev/null @@ -1,217 +0,0 @@ -import React from 'react'; -import lbry from 'lbry.js'; -import lbryuri from 'lbryuri.js'; -import Link from 'component/link'; -import {FormField} from 'component/form.js'; -import SubHeader from '../component/sub-header'; -import {FileTileStream} from 'component/fileTile'; -import rewards from 'rewards.js'; -import lbryio from 'lbryio.js'; -import {BusyMessage, Thumbnail} from 'component/common.js'; - -export let FileListNav = React.createClass({ - render: function() { - return ; - } -}); - -export let FileListDownloaded = React.createClass({ - _isMounted: false, - - getInitialState: function() { - return { - fileInfos: null, - }; - }, - componentDidMount: function() { - this._isMounted = true; - - lbry.claim_list_mine().then((myClaimInfos) => { - if (!this._isMounted) { return; } - - lbry.file_list().then((fileInfos) => { - if (!this._isMounted) { return; } - - const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); - this.setState({ - fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), - }); - }); - }); - }, - componentWillUnmount: function() { - this._isMounted = false; - }, - render: function() { - let content = ""; - if (this.state.fileInfos === null) { - content = ; - } else if (!this.state.fileInfos.length) { - content = You haven't downloaded anything from LBRY yet. Go !; - } else { - content = ; - } - return ( -
- - {content} -
- ); - } -}); - -export let FileListPublished = React.createClass({ - _isMounted: false, - - getInitialState: function () { - return { - fileInfos: null, - }; - }, - _requestPublishReward: function() { - lbryio.call('reward', 'list', {}).then(function(userRewards) { - //already rewarded - if (userRewards.filter(function (reward) { - return reward.RewardType == rewards.TYPE_FIRST_PUBLISH && reward.TransactionID; - }).length) { - return; - } - else { - rewards.claimReward(rewards.TYPE_FIRST_PUBLISH).catch(() => {}) - } - }, () => {}); - }, - componentDidMount: function () { - this._isMounted = true; - this._requestPublishReward(); - - lbry.claim_list_mine().then((claimInfos) => { - if (!this._isMounted) { return; } - - lbry.file_list().then((fileInfos) => { - if (!this._isMounted) { return; } - - const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout); - this.setState({ - fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), - }); - }); - }); - }, - componentWillUnmount: function() { - this._isMounted = false; - }, - render: function () { - let content = null; - if (this.state.fileInfos === null) { - content = ; - } - else if (!this.state.fileInfos.length) { - content = You haven't published anything to LBRY yet. Try !; - } - else { - content = ; - } - return ( -
- - {content} -
- ); - } -}); - -export let FileList = React.createClass({ - _sortFunctions: { - date: function(fileInfos) { - return fileInfos.slice().reverse(); - }, - title: function(fileInfos) { - return fileInfos.slice().sort(function(fileInfo1, fileInfo2) { - const title1 = fileInfo1.metadata ? fileInfo1.metadata.title.toLowerCase() : fileInfo1.name; - const title2 = fileInfo2.metadata ? fileInfo2.metadata.title.toLowerCase() : fileInfo2.name; - if (title1 < title2) { - return -1; - } else if (title1 > title2) { - return 1; - } else { - return 0; - } - }); - }, - filename: function(fileInfos) { - return fileInfos.slice().sort(function({file_name: fileName1}, {file_name: fileName2}) { - const fileName1Lower = fileName1.toLowerCase(); - const fileName2Lower = fileName2.toLowerCase(); - if (fileName1Lower < fileName2Lower) { - return -1; - } else if (fileName2Lower > fileName1Lower) { - return 1; - } else { - return 0; - } - }); - }, - }, - propTypes: { - fileInfos: React.PropTypes.array.isRequired, - hidePrices: React.PropTypes.bool, - }, - getDefaultProps: function() { - return { - hidePrices: false, - }; - }, - getInitialState: function() { - return { - sortBy: 'date', - }; - }, - handleSortChanged: function(event) { - this.setState({ - sortBy: event.target.value, - }); - }, - render: function() { - var content = [], - seenUris = {}; - - const fileInfosSorted = this._sortFunctions[this.state.sortBy](this.props.fileInfos); - for (let {outpoint, name, channel_name, metadata, mime_type, claim_id, has_signature, signature_is_valid} of fileInfosSorted) { - if (seenUris[name] || !claim_id) { - continue; - } - - let streamMetadata; - if (metadata) { - streamMetadata = metadata.stream.metadata; - } else { - streamMetadata = null; - } - - - const uri = lbryuri.build({contentName: name, channelName: channel_name}); - seenUris[name] = true; - content.push(); - } - - return ( -
- - Sort by { ' ' } - - - - - - - {content} -
- ); - } -}); \ No newline at end of file diff --git a/ui/js/page/fileListDownloaded/index.js b/ui/js/page/fileListDownloaded/index.js new file mode 100644 index 000000000..e808533bf --- /dev/null +++ b/ui/js/page/fileListDownloaded/index.js @@ -0,0 +1,17 @@ +import React from 'react' +import { + connect +} from 'react-redux' +import { + selectDownloadedContent, +} from 'selectors/content' +import FileListDownloaded from './view' + +const select = (state) => ({ + downloadedContent: selectDownloadedContent(state), +}) + +const perform = (dispatch) => ({ +}) + +export default connect(select, perform)(FileListDownloaded) diff --git a/ui/js/page/fileListDownloaded/view.jsx b/ui/js/page/fileListDownloaded/view.jsx new file mode 100644 index 000000000..8893a158b --- /dev/null +++ b/ui/js/page/fileListDownloaded/view.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import lbry from 'lbry.js'; +import lbryuri from 'lbryuri.js'; +import Link from 'component/link'; +import {FormField} from 'component/form.js'; +import {FileTileStream} from 'component/fileTile'; +import rewards from 'rewards.js'; +import lbryio from 'lbryio.js'; +import {BusyMessage, Thumbnail} from 'component/common.js'; +import FileList from 'component/fileList' + +const FileListDownloaded = (props) => { + // + return ( +
item
+ ) +} +// const FileListDownloaded = React.createClass({ +// _isMounted: false, + +// getInitialState: function() { +// return { +// fileInfos: null, +// }; +// }, +// componentDidMount: function() { +// this._isMounted = true; +// document.title = "Downloaded Files"; + +// lbry.claim_list_mine().then((myClaimInfos) => { +// if (!this._isMounted) { return; } + +// lbry.file_list().then((fileInfos) => { +// if (!this._isMounted) { return; } + +// const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); +// this.setState({ +// fileInfos: fileInfos.filter(({outpoint}) => !myClaimOutpoints.includes(outpoint)), +// }); +// }); +// }); +// }, +// componentWillUnmount: function() { +// this._isMounted = false; +// }, +// render: function() { +// if (this.state.fileInfos === null) { +// return ( +//
+// +//
+// ); +// } else if (!this.state.fileInfos.length) { +// return ( +//
+// You haven't downloaded anything from LBRY yet. Go ! +//
+// ); +// } else { +// return ( +//
+// +//
+// ); +// } +// } +// }); + +export default FileListDownloaded diff --git a/ui/js/page/fileListPublished/index.js b/ui/js/page/fileListPublished/index.js new file mode 100644 index 000000000..3bf2724cf --- /dev/null +++ b/ui/js/page/fileListPublished/index.js @@ -0,0 +1,7 @@ +import React from 'react' +import { + connect +} from 'react-redux' +import FileListPublished from './view' + +export default connect()(FileListPublished) diff --git a/ui/js/page/fileListPublished/view.jsx b/ui/js/page/fileListPublished/view.jsx new file mode 100644 index 000000000..70d170079 --- /dev/null +++ b/ui/js/page/fileListPublished/view.jsx @@ -0,0 +1,86 @@ +import React from 'react'; +import lbry from 'lbry.js'; +import lbryuri from 'lbryuri.js'; +import Link from 'component/link'; +import {FormField} from 'component/form.js'; +import {FileTileStream} from 'component/fileTile'; +import rewards from 'rewards.js'; +import lbryio from 'lbryio.js'; +import {BusyMessage, Thumbnail} from 'component/common.js'; +import FileList from 'component/fileList' + +const FileListPublished = (props) => { + // + return ( +
published content
+ ) +} + +// const FileListPublished = React.createClass({ +// _isMounted: false, + +// getInitialState: function () { +// return { +// fileInfos: null, +// }; +// }, +// _requestPublishReward: function() { +// lbryio.call('reward', 'list', {}).then(function(userRewards) { +// //already rewarded +// if (userRewards.filter(function (reward) { +// return reward.RewardType == rewards.TYPE_FIRST_PUBLISH && reward.TransactionID; +// }).length) { +// return; +// } +// else { +// rewards.claimReward(rewards.TYPE_FIRST_PUBLISH).catch(() => {}) +// } +// }); +// }, +// componentDidMount: function () { +// this._isMounted = true; +// this._requestPublishReward(); +// document.title = "Published Files"; + +// lbry.claim_list_mine().then((claimInfos) => { +// if (!this._isMounted) { return; } + +// lbry.file_list().then((fileInfos) => { +// if (!this._isMounted) { return; } + +// const myClaimOutpoints = claimInfos.map(({txid, nout}) => txid + ':' + nout); +// this.setState({ +// fileInfos: fileInfos.filter(({outpoint}) => myClaimOutpoints.includes(outpoint)), +// }); +// }); +// }); +// }, +// componentWillUnmount: function() { +// this._isMounted = false; +// }, +// render: function () { +// if (this.state.fileInfos === null) { +// return ( +//
+// +//
+// ); +// } +// else if (!this.state.fileInfos.length) { +// return ( +//
+// You haven't published anything to LBRY yet. Try ! +//
+// ); +// } +// else { +// return ( +//
+// +//
+// ); +// } +// } +// }); + +export default FileListPublished diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js index 5b9cc2e04..496bdcb79 100644 --- a/ui/js/reducers/content.js +++ b/ui/js/reducers/content.js @@ -66,6 +66,46 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { return Object.assign({}, state, newState) } +reducers[types.FETCH_DOWNLOADED_CONTENT_STARTED] = function(state, action) { + return Object.assign({}, state, { + fetchingDownloadedContent: true, + }) +} + +reducers[types.FETCH_DOWNLOADED_CONTENT_COMPLETED] = function(state, action) { + const { + fileInfos + } = action.data + const newDownloadedContent = Object.assign({}, state.downloadedContent, { + fileInfos + }) + + return Object.assign({}, state, { + downloadedContent: newDownloadedContent, + fetchingDownloadedContent: false, + }) +} + +reducers[types.FETCH_PUBLISHED_CONTENT_STARTED] = function(state, action) { + return Object.assign({}, state, { + fetchingPublishedContent: true, + }) +} + +reducers[types.FETCH_PUBLISHED_CONTENT_COMPLETED] = function(state, action) { + const { + fileInfos + } = action.data + const newPublishedContent = Object.assign({}, state.publishedContent, { + fileInfos + }) + + return Object.assign({}, state, { + publishedContent: newPublishedContent, + fetchingPublishedContent: false, + }) +} + 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 e2222cb91..f854cf90d 100644 --- a/ui/js/selectors/content.js +++ b/ui/js/selectors/content.js @@ -40,3 +40,53 @@ export const selectResolvedUris = createSelector( _selectState, (state) => state.resolvedUris || {} ) + +export const selectFetchingDownloadedContent = createSelector( + _selectState, + (state) => !!state.fetchingDownloadedContent +) + +export const selectDownloadedContent = createSelector( + _selectState, + (state) => state.downloadedContent || {} +) + +export const shouldFetchDownloadedContent = createSelector( + selectDaemonReady, + selectCurrentPage, + selectFetchingDownloadedContent, + selectDownloadedContent, + (daemonReady, page, fetching, content) => { + if (!daemonReady) return false + if (page != 'downloaded') return false + if (fetching) return false + if (Object.keys(content).length != 0) return false + + return true + } +) + +export const selectFetchingPublishedContent = createSelector( + _selectState, + (state) => !!state.fetchingPublishedContent +) + +export const selectPublishedContent = createSelector( + _selectState, + (state) => state.publishedContent || {} +) + +export const shouldFetchPublishedContent = createSelector( + selectDaemonReady, + selectCurrentPage, + selectFetchingPublishedContent, + selectPublishedContent, + (daemonReady, page, fetching, content) => { + if (!daemonReady) return false + if (page != 'published') return false + if (fetching) return false + if (Object.keys(content).length != 0) return false + + return true + } +) diff --git a/ui/js/triggers.js b/ui/js/triggers.js index 8fe951df8..e6e360220 100644 --- a/ui/js/triggers.js +++ b/ui/js/triggers.js @@ -4,6 +4,8 @@ import { } from 'selectors/wallet' import { shouldFetchFeaturedContent, + shouldFetchDownloadedContent, + shouldFetchPublishedContent, } from 'selectors/content' import { doFetchTransactions, @@ -11,6 +13,8 @@ import { } from 'actions/wallet' import { doFetchFeaturedContent, + doFetchDownloadedContent, + doFetchPublishedContent, } from 'actions/content' const triggers = [] @@ -30,6 +34,18 @@ triggers.push({ action: doFetchFeaturedContent, }) +triggers.push({ + selector: shouldFetchDownloadedContent, + action: doFetchDownloadedContent, +}) + +triggers.push({ + selector: shouldFetchPublishedContent, + action: doFetchPublishedContent, +}) + +console.log(triggers) + const runTriggers = function() { triggers.forEach(function(trigger) { const state = app.store.getState();