Downloaded file list kind of working. Not sure about sort.
This commit is contained in:
parent
12f965f473
commit
d2e7d7f1df
12 changed files with 291 additions and 135 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) => ({
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue