Downloaded file list kind of working. Not sure about sort.

This commit is contained in:
6ea86b96 2017-04-30 23:01:43 +07:00 committed by Jeremy Kauffman
parent 12f965f473
commit d2e7d7f1df
12 changed files with 291 additions and 135 deletions

View file

@ -5,6 +5,7 @@ import {
selectUpgradeDownloadDir, selectUpgradeDownloadDir,
selectUpgradeDownloadItem, selectUpgradeDownloadItem,
selectUpgradeFilename, selectUpgradeFilename,
selectPageTitle,
} from 'selectors/app' } from 'selectors/app'
const {remote, ipcRenderer, shell} = require('electron'); const {remote, ipcRenderer, shell} = require('electron');
@ -14,11 +15,17 @@ const {download} = remote.require('electron-dl');
const fs = remote.require('fs'); const fs = remote.require('fs');
export function doNavigate(path) { export function doNavigate(path) {
return { return function(dispatch, getState) {
dispatch({
type: types.NAVIGATE, type: types.NAVIGATE,
data: { data: {
path: path path,
} }
})
const state = getState()
const pageTitle = selectPageTitle(state)
window.document.title = pageTitle
} }
} }

View file

@ -20,6 +20,9 @@ import {
import { import {
selectCurrentResolvedUriClaimOutpoint, selectCurrentResolvedUriClaimOutpoint,
} from 'selectors/content' } from 'selectors/content'
import {
selectClaimsByUri,
} from 'selectors/claims'
import { import {
doOpenModal, doOpenModal,
} from 'actions/app' } from 'actions/app'
@ -67,6 +70,15 @@ export function doFetchDownloadedContent() {
lbry.file_list().then((fileInfos) => { lbry.file_list().then((fileInfos) => {
const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout); const myClaimOutpoints = myClaimInfos.map(({txid, nout}) => txid + ':' + nout);
fileInfos.forEach(fileInfo => {
const uri = lbryuri.build({
channelName: fileInfo.channel_name,
contentName: fileInfo.name,
})
const claim = selectClaimsByUri(state)[uri]
if (!claim) dispatch(doResolveUri(uri))
})
dispatch({ dispatch({
type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED, type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED,
data: { data: {

View file

@ -76,3 +76,27 @@ export function doDeleteFile(uri, fileInfo, deleteFromComputer) {
lbry.removeFile(fileInfo.outpoint, deleteFromComputer, successCallback) lbry.removeFile(fileInfo.outpoint, deleteFromComputer, successCallback)
} }
} }
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)),
}
})
});
});
}
}

View file

@ -4,4 +4,10 @@ import {
} from 'react-redux' } from 'react-redux'
import FileList from './view' import FileList from './view'
export default connect()(FileList) const select = (state) => ({
})
const perform = (dispatch) => ({
})
export default connect(select, perform)(FileList)

View file

@ -3,20 +3,27 @@ import lbry from 'lbry.js';
import lbryuri from 'lbryuri.js'; import lbryuri from 'lbryuri.js';
import Link from 'component/link'; import Link from 'component/link';
import {FormField} from 'component/form.js'; import {FormField} from 'component/form.js';
import FileTileStream from 'component/fileTile'; import FileTileStream from 'component/fileTileStream';
import rewards from 'rewards.js'; import rewards from 'rewards.js';
import lbryio from 'lbryio.js'; import lbryio from 'lbryio.js';
import {BusyMessage, Thumbnail} from 'component/common.js'; import {BusyMessage, Thumbnail} from 'component/common.js';
const FileList = React.createClass({ class FileList extends React.Component {
_sortFunctions: { constructor(props) {
super(props)
this.state = {
sortBy: 'date',
}
this._sortFunctions = {
date: function(fileInfos) { date: function(fileInfos) {
return fileInfos.slice().reverse(); return fileInfos.slice().reverse();
}, },
title: function(fileInfos) { title: function(fileInfos) {
return fileInfos.slice().sort(function(fileInfo1, fileInfo2) { return fileInfos.slice().sort(function(fileInfo1, fileInfo2) {
const title1 = fileInfo1.metadata ? fileInfo1.metadata.title.toLowerCase() : fileInfo1.name; const title1 = fileInfo1.metadata ? fileInfo1.metadata.stream.metadata.title.toLowerCase() : fileInfo1.name;
const title2 = fileInfo2.metadata ? fileInfo2.metadata.title.toLowerCase() : fileInfo2.name; const title2 = fileInfo2.metadata ? fileInfo2.metadata.stream.metadata.title.toLowerCase() : fileInfo2.name;
if (title1 < title2) { if (title1 < title2) {
return -1; return -1;
} else if (title1 > title2) { } else if (title1 > title2) {
@ -24,7 +31,7 @@ const FileList = React.createClass({
} else { } else {
return 0; return 0;
} }
}); })
}, },
filename: function(fileInfos) { filename: function(fileInfos) {
return fileInfos.slice().sort(function({file_name: fileName1}, {file_name: fileName2}) { return fileInfos.slice().sort(function({file_name: fileName1}, {file_name: fileName2}) {
@ -37,56 +44,40 @@ const FileList = React.createClass({
} else { } else {
return 0; return 0;
} }
}); })
}, },
}, }
propTypes: { }
fileInfos: React.PropTypes.array.isRequired,
hidePrices: React.PropTypes.bool, handleSortChanged(event) {
},
getDefaultProps: function() {
return {
hidePrices: false,
};
},
getInitialState: function() {
return {
sortBy: 'date',
};
},
handleSortChanged: function(event) {
this.setState({ this.setState({
sortBy: event.target.value, 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; render() {
if (metadata) { const {
streamMetadata = metadata.stream.metadata; handleSortChanged,
} else { fileInfos,
streamMetadata = null; hidePrices,
} } = this.props
const {
sortBy,
const uri = lbryuri.build({contentName: name, channelName: channel_name}); } = this.state
seenUris[name] = true; const content = []
content.push(<FileTileStream key={outpoint} uri={uri} hideOnRemove={true} />)
}
this._sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
const uri = lbryuri.build({
contentName: fileInfo.name,
channelName: fileInfo.channel_name,
})
content.push(<FileTileStream key={uri} uri={uri} hidePrice={hidePrices} />)
})
return ( return (
<section> <section>
<span className='sort-section'> <span className='sort-section'>
Sort by { ' ' } Sort by { ' ' }
<FormField type="select" onChange={this.handleSortChanged}> <FormField type="select" onChange={this.handleSortChanged.bind(this)}>
<option value="date">Date</option> <option value="date">Date</option>
<option value="title">Title</option> <option value="title">Title</option>
<option value="filename">File name</option> <option value="filename">File name</option>
@ -94,8 +85,100 @@ const FileList = React.createClass({
</span> </span>
{content} {content}
</section> </section>
); )
} }
}); }
// 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 = {};
// console.debug(this.props)
// 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(<FileTileStream key={outpoint} uri={uri} hideOnRemove={true} />)
// }
// return (
// <section>
// <span className='sort-section'>
// Sort by { ' ' }
// <FormField type="select" onChange={this.handleSortChanged}>
// <option value="date">Date</option>
// <option value="title">Title</option>
// <option value="filename">File name</option>
// </FormField>
// </span>
// {content}
// </section>
// );
// }
// });
export default FileList export default FileList

View file

@ -5,6 +5,7 @@ import {
import { import {
selectCurrentPage, selectCurrentPage,
selectHeaderLinks, selectHeaderLinks,
selectPageTitle,
} from 'selectors/app' } from 'selectors/app'
import { import {
doNavigate, doNavigate,
@ -19,6 +20,7 @@ import Header from './view'
const select = (state) => ({ const select = (state) => ({
currentPage: selectCurrentPage(state), currentPage: selectCurrentPage(state),
subLinks: selectHeaderLinks(state), subLinks: selectHeaderLinks(state),
pageTitle: selectPageTitle(state),
}) })
const perform = (dispatch) => ({ const perform = (dispatch) => ({

View file

@ -3,17 +3,23 @@ import {
connect connect
} from 'react-redux' } from 'react-redux'
import { import {
selectDownloadedContentFileInfos,
selectFetchingDownloadedContent, selectFetchingDownloadedContent,
} from 'selectors/content' } from 'selectors/content'
import {
selectDownloadedFileInfo,
} from 'selectors/file_info'
import {
doNavigate,
} from 'actions/app'
import FileListDownloaded from './view' import FileListDownloaded from './view'
const select = (state) => ({ const select = (state) => ({
downloadedContent: selectDownloadedContentFileInfos(state), downloadedContent: selectDownloadedFileInfo(state),
fetching: selectFetchingDownloadedContent(state), fetching: selectFetchingDownloadedContent(state),
}) })
const perform = (dispatch) => ({ const perform = (dispatch) => ({
navigate: (path) => dispatch(doNavigate(path)),
}) })
export default connect(select, perform)(FileListDownloaded) export default connect(select, perform)(FileListDownloaded)

View file

@ -14,6 +14,7 @@ class FileListDownloaded extends React.Component {
const { const {
downloadedContent, downloadedContent,
fetching, fetching,
navigate,
} = this.props } = this.props
if (fetching) { if (fetching) {
@ -25,7 +26,7 @@ class FileListDownloaded extends React.Component {
} else if (!downloadedContent.length) { } else if (!downloadedContent.length) {
return ( return (
<main className="page"> <main className="page">
<span>You haven't downloaded anything from LBRY yet. Go <Link href="?discover" label="search for your first download" />!</span> <span>You haven't downloaded anything from LBRY yet. Go <Link href="#" onClick={() => navigate('discover')} label="search for your first download" />!</span>
</main> </main>
); );
} else { } else {
@ -37,55 +38,5 @@ class FileListDownloaded extends React.Component {
} }
} }
} }
// 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 (
// <main className="page">
// <BusyMessage message="Loading" />
// </main>
// );
// } else if (!this.state.fileInfos.length) {
// return (
// <main className="page">
// <span>You haven't downloaded anything from LBRY yet. Go <Link href="?discover" label="search for your first download" />!</span>
// </main>
// );
// } else {
// return (
// <main className="page">
// <FileList fileInfos={this.state.fileInfos} hidePrices={true} />
// </main>
// );
// }
// }
// });
export default FileListDownloaded export default FileListDownloaded

View file

@ -1,4 +1,5 @@
import * as types from 'constants/action_types' import * as types from 'constants/action_types'
import lbryuri from 'lbryuri'
const reducers = {} const reducers = {}
const defaultState = { const defaultState = {
@ -157,6 +158,26 @@ reducers[types.LOADING_VIDEO_FAILED] = function(state, action) {
}) })
} }
reducers[types.FETCH_DOWNLOADED_CONTENT_COMPLETED] = function(state, action) {
const {
fileInfos,
} = action.data
const newByUri = Object.assign({}, state.byUri)
fileInfos.forEach(fileInfo => {
const uri = lbryuri.build({
channelName: fileInfo.channel_name,
contentName: fileInfo.name,
})
newByUri[uri] = fileInfo
})
return Object.assign({}, state, {
byUri: newByUri
})
}
export default function reducer(state = defaultState, action) { export default function reducer(state = defaultState, action) {
const handler = reducers[action.type]; const handler = reducers[action.type];
if (handler) return handler(state, action); if (handler) return handler(state, action);

View file

@ -28,6 +28,34 @@ export const selectCurrentUri = createSelector(
} }
) )
export const selectPageTitle = createSelector(
selectCurrentPage,
selectCurrentUri,
(page, uri) => {
switch(page)
{
case 'discover':
return 'Discover'
case 'wallet':
case 'send':
case 'receive':
case 'claim':
case 'referral':
return 'Wallet'
case 'downloaded':
return 'My Files'
case 'published':
return 'My Files'
case 'publish':
return 'Publish'
case 'help':
return 'Help'
default:
return 'LBRY';
}
}
)
export const selectPlatform = createSelector( export const selectPlatform = createSelector(
_selectState, _selectState,
(state) => state.platform (state) => state.platform

View file

@ -133,3 +133,19 @@ export const makeSelectLoadingForUri = () => {
(loading) => !!loading (loading) => !!loading
) )
} }
export const selectDownloadedFileInfo = createSelector(
selectAllFileInfoByUri,
(byUri) => {
const fileInfoList = []
Object.keys(byUri).forEach(key => {
const fileInfo = byUri[key]
if (fileInfo.completed || fileInfo.written_bytes) {
fileInfoList.push(fileInfo)
}
})
return fileInfoList
}
)