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

View file

@ -20,6 +20,9 @@ import {
import {
selectCurrentResolvedUriClaimOutpoint,
} from 'selectors/content'
import {
selectClaimsByUri,
} from 'selectors/claims'
import {
doOpenModal,
} from 'actions/app'
@ -67,6 +70,15 @@ export function doFetchDownloadedContent() {
lbry.file_list().then((fileInfos) => {
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({
type: types.FETCH_DOWNLOADED_CONTENT_COMPLETED,
data: {

View file

@ -76,3 +76,27 @@ export function doDeleteFile(uri, fileInfo, deleteFromComputer) {
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'
import FileList from './view'
export default connect()(FileList)
const select = (state) => ({
})
const perform = (dispatch) => ({
})
export default connect(select, perform)(FileList)

View file

@ -3,90 +3,81 @@ 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 FileTileStream from 'component/fileTileStream';
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 {
class FileList extends React.Component {
constructor(props) {
super(props)
this.state = {
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(<FileTileStream key={outpoint} uri={uri} hideOnRemove={true} />)
}
this._sortFunctions = {
date: function(fileInfos) {
return fileInfos.slice().reverse();
},
title: function(fileInfos) {
return fileInfos.slice().sort(function(fileInfo1, fileInfo2) {
const title1 = fileInfo1.metadata ? fileInfo1.metadata.stream.metadata.title.toLowerCase() : fileInfo1.name;
const title2 = fileInfo2.metadata ? fileInfo2.metadata.stream.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;
}
})
},
}
}
handleSortChanged(event) {
this.setState({
sortBy: event.target.value,
})
}
render() {
const {
handleSortChanged,
fileInfos,
hidePrices,
} = this.props
const {
sortBy,
} = this.state
const content = []
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 (
<section>
<span className='sort-section'>
Sort by { ' ' }
<FormField type="select" onChange={this.handleSortChanged}>
<FormField type="select" onChange={this.handleSortChanged.bind(this)}>
<option value="date">Date</option>
<option value="title">Title</option>
<option value="filename">File name</option>
@ -94,8 +85,100 @@ const FileList = React.createClass({
</span>
{content}
</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

View file

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

View file

@ -104,7 +104,7 @@ class WunderBar extends React.PureComponent {
this.props.onSearch(searchTerm);
}, 800); // 800ms delay, tweak for faster/slower
}
componentWillReceiveProps(nextProps) {
if (nextProps.viewingPage !== this.props.viewingPage || nextProps.address != this.props.address) {
this.setState({ address: nextProps.address, icon: nextProps.icon });

View file

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

View file

@ -14,6 +14,7 @@ class FileListDownloaded extends React.Component {
const {
downloadedContent,
fetching,
navigate,
} = this.props
if (fetching) {
@ -25,7 +26,7 @@ class FileListDownloaded extends React.Component {
} else if (!downloadedContent.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>
<span>You haven't downloaded anything from LBRY yet. Go <Link href="#" onClick={() => navigate('discover')} label="search for your first download" />!</span>
</main>
);
} 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

View file

@ -1,4 +1,5 @@
import * as types from 'constants/action_types'
import lbryuri from 'lbryuri'
const reducers = {}
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) {
const handler = reducers[action.type];
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(
_selectState,
(state) => state.platform

View file

@ -133,3 +133,19 @@ export const makeSelectLoadingForUri = () => {
(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
}
)