lbry-desktop/js/page/my_files.js

294 lines
9 KiB
JavaScript
Raw Normal View History

2016-11-22 21:19:08 +01:00
import React from 'react';
import lbry from '../lbry.js';
import {Link, WatchLink} from '../component/link.js';
2016-12-07 22:24:33 +01:00
import {Menu, MenuItem} from '../component/menu.js';
import FormField from '../component/form.js';
import FileTile from '../component/file-tile.js';
2016-11-22 21:19:08 +01:00
import Modal from '../component/modal.js';
import {BusyMessage, Thumbnail} from '../component/common.js';
var moreMenuStyle = {
position: 'absolute',
display: 'block',
top: '26px',
right: '13px',
};
var MyFilesRowMoreMenu = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
path: React.PropTypes.string.isRequired,
completed: React.PropTypes.bool.isRequired,
lbryUri: React.PropTypes.string.isRequired,
},
handleRevealClicked: function() {
lbry.revealFile(this.props.path);
},
handleRemoveClicked: function() {
lbry.deleteFile(this.props.lbryUri, false);
},
handleDeleteClicked: function() {
this.setState({
modal: 'confirmDelete',
});
},
handleDeleteConfirmed: function() {
lbry.deleteFile(this.props.lbryUri);
this.setState({
modal: null,
});
},
closeModal: function() {
this.setState({
modal: null,
});
},
getInitialState: function() {
return {
modal: null,
};
},
render: function() {
return (
<div style={moreMenuStyle}>
<Menu {...this.props}>
2016-08-08 05:31:21 +02:00
<section className="card">
<MenuItem onClick={this.handleRevealClicked} label="Reveal file" /> {/* @TODO: Switch to OS specific wording */}
<MenuItem onClick={this.handleRemoveClicked} label="Remove from LBRY" />
<MenuItem onClick={this.handleDeleteClicked} label="Remove and delete file" />
2016-08-08 05:31:21 +02:00
</section>
</Menu>
2017-01-13 23:05:09 +01:00
<Modal isOpen={this.state.modal == 'confirmDelete'} contentLabel="Confirm delete" type="confirm" confirmButtonLabel="Delete File"
onConfirmed={this.handleDeleteConfirmed} onAborted={this.closeModal}>
Are you sure you'd like to delete <cite>{this.props.title}</cite>? This will {this.props.completed ? ' stop the download and ' : ''}
permanently remove the file from your system.
</Modal>
</div>
);
}
});
var moreButtonColumnStyle = {
2016-08-07 17:27:00 +02:00
height: '120px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
moreButtonContainerStyle = {
display: 'block',
position: 'relative',
},
moreButtonStyle = {
fontSize: '1.3em',
},
progressBarStyle = {
height: '15px',
width: '230px',
backgroundColor: '#444',
border: '2px solid #eee',
display: 'inline-block',
},
2016-08-07 17:27:00 +02:00
artStyle = {
maxHeight: '100px',
2016-08-26 12:54:30 +02:00
maxWidth: '100%',
2016-08-07 17:27:00 +02:00
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
};
2016-05-16 10:19:41 +02:00
2016-05-10 12:36:54 +02:00
var MyFilesPage = React.createClass({
_fileTimeout: null,
_fileInfoCheckRate: 300,
_fileInfoCheckNum: 0,
2016-11-18 11:54:57 +01:00
_sortFunctions: {
date: function(filesInfo) {
return filesInfo.reverse();
},
title: function(filesInfo) {
return filesInfo.sort(function(a, b) {
return ((a.metadata ? a.metadata.title.toLowerCase() : a.name) >
(b.metadata ? b.metadata.title.toLowerCase() : b.name));
});
},
filename: function(filesInfo) {
return filesInfo.sort(function(a, b) {
return (a.file_name.toLowerCase() >
b.file_name.toLowerCase());
});
},
},
2016-05-10 12:36:54 +02:00
getInitialState: function() {
return {
filesInfo: null,
publishedFilesSdHashes: null,
filesAvailable: null,
2016-11-18 11:56:55 +01:00
sortBy: 'date',
2016-05-10 12:36:54 +02:00
};
},
getDefaultProps: function() {
return {
show: null,
};
},
componentDidMount: function() {
document.title = "My Files";
},
2016-05-10 12:36:54 +02:00
componentWillMount: function() {
if (this.props.show == 'downloaded') {
this.getPublishedFilesSdHashes(() => {
this.updateFilesInfo();
});
} else {
this.updateFilesInfo();
}
},
getPublishedFilesSdHashes: function(callback) {
// Determines which files were published by the user and saves their SD hashes in
// this.state.publishedFilesSdHashes. Used on the Downloads page to filter out claims published
// by the user.
var publishedFilesSdHashes = [];
lbry.getMyClaims((claimsInfo) => {
for (let claimInfo of claimsInfo) {
let metadata = JSON.parse(claimInfo.value);
publishedFilesSdHashes.push(metadata.sources.lbry_sd_hash);
}
this.setState({
publishedFilesSdHashes: publishedFilesSdHashes,
});
callback();
});
},
2016-08-08 02:57:12 +02:00
componentWillUnmount: function() {
if (this._fileTimeout)
2016-08-08 02:57:12 +02:00
{
clearTimeout(this._fileTimeout);
2016-08-08 02:57:12 +02:00
}
},
2016-11-18 11:56:55 +01:00
handleSortChanged: function(event) {
this.setState({
sortBy: event.target.value,
});
},
updateFilesInfo: function() {
this._fileInfoCheckNum += 1;
if (this.props.show == 'published') {
// We're in the Published tab, so populate this.state.filesInfo with data from the user's claims
lbry.getMyClaims((claimsInfo) => {
/**
* Build newFilesInfo as a sparse array and drop elements in at the same position they
* occur in claimsInfo, so the order is preserved even if the API calls inside this loop
* return out of order.
*/
let newFilesInfo = Array(claimsInfo.length);
let claimInfoProcessedCount = 0;
for (let [i, claimInfo] of claimsInfo.entries()) {
let metadata = JSON.parse(claimInfo.value);
lbry.getFileInfoBySdHash(metadata.sources.lbry_sd_hash, (fileInfo) => {
claimInfoProcessedCount++;
if (fileInfo !== false) {
newFilesInfo[i] = fileInfo;
}
if (claimInfoProcessedCount >= claimsInfo.length) {
/**
* newFilesInfo may have gaps from claims that don't have associated files in
* lbrynet, so filter out any missing elements
*/
2017-01-04 01:09:46 +01:00
this.setState({
filesInfo: newFilesInfo.filter(function() { return true }),
2017-01-04 01:09:46 +01:00
});
this._fileTimeout = setTimeout(() => { this.updateFilesInfo() }, 1000);
}
});
}
});
} else {
// We're in the Downloaded tab, so populate this.state.filesInfo with files the user has in
// lbrynet, with published files filtered out.
lbry.getFilesInfo((filesInfo) => {
2017-01-04 01:09:46 +01:00
this.setState({
filesInfo: filesInfo.filter(({sd_hash}) => {
return this.state.publishedFilesSdHashes.indexOf(sd_hash) == -1;
}),
});
let newFilesAvailable;
if (!(this._fileInfoCheckNum % this._fileInfoCheckRate)) {
// Time to update file availability status
newFilesAvailable = {};
let filePeersCheckCount = 0;
for (let {sd_hash} of filesInfo) {
lbry.getPeersForBlobHash(sd_hash, (peers) => {
filePeersCheckCount++;
newFilesAvailable[sd_hash] = peers.length >= 0;
if (filePeersCheckCount >= filesInfo.length) {
this.setState({
filesAvailable: newFilesAvailable,
});
}
});
}
}
this._fileTimeout = setTimeout(() => { this.updateFilesInfo() }, 1000);
})
}
2016-05-10 12:36:54 +02:00
},
render: function() {
if (this.state.filesInfo === null || (this.props.show == 'downloaded' && this.state.publishedFileSdHashes === null)) {
return (
<main className="page">
<BusyMessage message="Loading" />
</main>
);
} else if (!this.state.filesInfo.length) {
return (
<main className="page">
{this.props.show == 'downloaded'
? <span>You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!</span>
: <span>You haven't published anything to LBRY yet.</span>}
</main>
);
2016-05-10 12:36:54 +02:00
} else {
2016-08-07 17:27:00 +02:00
var content = [],
2016-08-07 17:29:08 +02:00
seenUris = {};
2017-01-04 01:09:46 +01:00
const filesInfoSorted = this._sortFunctions[this.state.sortBy](this.state.filesInfo);
for (let fileInfo of filesInfoSorted) {
let {completed, lbry_uri, sd_hash, metadata, download_path, stopped, pending} = fileInfo;
if (!metadata || seenUris[lbry_uri]) {
continue;
}
2016-08-07 17:29:08 +02:00
seenUris[lbry_uri] = true;
content.push(<FileTile name={lbry_uri} sdHash={sd_hash} isMine={this.props.show == 'published'} local={true}
metadata={metadata} completed={completed} stopped={stopped} pending={pending} path={download_path}
{... this.state.filesAvailable !== null ? {available: this.state.filesAvailable[sd_hash]} : {}} />);
2016-05-10 12:36:54 +02:00
}
}
2016-05-16 10:19:41 +02:00
return (
<main className="page">
2016-11-18 11:56:55 +01:00
<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>
2016-08-08 05:31:21 +02:00
{content}
2016-05-16 10:19:41 +02:00
</main>
);
2016-05-10 12:36:54 +02:00
}
});
2016-11-22 21:19:08 +01:00
export default MyFilesPage;