From 7f135275df0f6e0cecf5d4f8b9a933570c1acae7 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Fri, 13 Jan 2017 17:18:37 -0500 Subject: [PATCH] file list refactor --- js/app.js | 6 +- js/component/file-actions.js | 24 ++--- js/component/file-tile.js | 20 +--- js/lbry.js | 28 ++--- js/page/file-list.js | 194 ++++++++++++++++++++++++++++++++++ js/page/my_files.js | 196 ----------------------------------- scss/_gui.scss | 11 +- 7 files changed, 225 insertions(+), 254 deletions(-) create mode 100644 js/page/file-list.js delete mode 100644 js/page/my_files.js diff --git a/js/app.js b/js/app.js index 0d7c3848a..68c03a648 100644 --- a/js/app.js +++ b/js/app.js @@ -4,7 +4,6 @@ import SettingsPage from './page/settings.js'; import HelpPage from './page/help.js'; import WatchPage from './page/watch.js'; import ReportPage from './page/report.js'; -import {MyFilesPage} from './page/my_files.js'; import StartPage from './page/start.js'; import ClaimCodePage from './page/claim_code.js'; import ReferralPage from './page/referral.js'; @@ -14,6 +13,7 @@ import PublishPage from './page/publish.js'; import DiscoverPage from './page/discover.js'; import SplashScreen from './component/splash.js'; import DeveloperPage from './page/developer.js'; +import {FileListDownloaded, FileListPublished} from './page/file-list.js'; import Drawer from './component/drawer.js'; import Header from './component/header.js'; import Modal from './component/modal.js'; @@ -164,9 +164,9 @@ var App = React.createClass({ case 'report': return ; case 'downloaded': - return ; + return ; case 'published': - return ; + return ; case 'start': return ; case 'claim': diff --git a/js/component/file-actions.js b/js/component/file-actions.js index a89cdfab2..9dc70c476 100644 --- a/js/component/file-actions.js +++ b/js/component/file-actions.js @@ -56,11 +56,10 @@ export let FileActions = React.createClass({ propTypes: { streamName: React.PropTypes.string, - sdHash: React.PropTypes.string, + sdHash: React.PropTypes.string.isRequired, metadata: React.PropTypes.object, path: React.PropTypes.string, hidden: React.PropTypes.bool, - onRemoveConfirmed: React.PropTypes.func, deleteChecked: React.PropTypes.bool, }, getInitialState: function() { @@ -137,9 +136,10 @@ export let FileActions = React.createClass({ }); }, handleRemoveConfirmed: function() { - lbry.deleteFile(this.props.sdHash || this.props.streamName, this.state.deleteChecked); - if (this.props.onRemoveConfirmed) { - this.props.onRemoveConfirmed(); + if (this.props.streamName) { + lbry.deleteFile(this.props.streamName, this.state.deleteChecked); + } else { + alert('this file cannot be deleted because lbry is a retarded piece of shit'); } this.setState({ modal: null, @@ -155,20 +155,12 @@ export let FileActions = React.createClass({ }, componentDidMount: function() { this._isMounted = true; - - if ('sdHash' in this.props) { - alert('render by sd hash is broken'); - lbry.fileInfoSubscribeByStreamHash(this.props.sdHash, this.fileInfoU); - } else if ('streamName' in this.props) { - this._fileInfoSubscribeId = lbry.fileInfoSubscribeByName(this.props.streamName, this.onFileInfoUpdate); - } else { - throw new Error("No stream name or sd hash passed to FileTile"); - } + this._fileInfoSubscribeId = lbry.fileInfoSubscribe(this.props.sdHash, this.onFileInfoUpdate); }, componentWillUnmount: function() { this._isMounted = false; if (this._fileInfoSubscribeId) { - lbry.fileInfoUnsubscribe(this.props.streamName, this._fileInfoSubscribeId); + lbry.fileInfoUnsubscribe(this.props.sdHash, this._fileInfoSubscribeId); } }, render: function() { @@ -178,7 +170,7 @@ export let FileActions = React.createClass({ } const openInFolderMessage = window.navigator.platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder', showMenu = !this.state.attemptingRemove && this.state.fileInfo !== null; - + let linkBlock; if (this.state.attemptingRemove || (this.state.fileInfo === false && !this.state.attemptingDownload)) { linkBlock = ; diff --git a/js/component/file-tile.js b/js/component/file-tile.js index a7ee08eb4..27b65c691 100644 --- a/js/component/file-tile.js +++ b/js/component/file-tile.js @@ -55,8 +55,7 @@ export let FileTileStream = React.createClass({ metadata: React.PropTypes.object, sdHash: React.PropTypes.string, hidePrice: React.PropTypes.bool, - obscureNsfw: React.PropTypes.bool, - hideOnRemove: React.PropTypes.bool + obscureNsfw: React.PropTypes.bool }, getInitialState: function() { return { @@ -66,7 +65,6 @@ export let FileTileStream = React.createClass({ }, getDefaultProps: function() { return { - hideOnRemove: false, obscureNsfw: !lbry.getClientSetting('showNsfw'), hidePrice: false } @@ -85,19 +83,11 @@ export let FileTileStream = React.createClass({ }); } }, - onRemove: function() { - this.setState({ - isRemoved: true, - }); - }, render: function() { - if (this.props.metadata === null || (this.props.hideOnRemove && this.state.isRemoved)) { - return null; - } - const metadata = this.props.metadata || {}, obscureNsfw = this.props.obscureNsfw && metadata.nsfw, title = metadata.title ? metadata.title : ('lbry://' + this.props.name); + return (
@@ -116,7 +106,7 @@ export let FileTileStream = React.createClass({ - +

{metadata.description} @@ -141,7 +131,7 @@ export let FileTile = React.createClass({ _isMounted: false, propTypes: { - name: React.PropTypes.string + name: React.PropTypes.string.isRequired }, getInitialState: function() { @@ -167,7 +157,7 @@ export let FileTile = React.createClass({ this._isMounted = false; }, render: function() { - if (this.state.metadata === null || this.state.sdHash === null) { + if (!this.state.metadata || !this.state.sdHash) { return null; } diff --git a/js/lbry.js b/js/lbry.js index d79bb8454..925f13b34 100644 --- a/js/lbry.js +++ b/js/lbry.js @@ -472,43 +472,37 @@ lbry._updateClaimOwnershipCache = function(claimId) { }); }; -lbry._updateSubscribedFileInfoByName = function(name) { - lbry.getFileInfoByName(name, (fileInfo) => { +lbry._updateSubscribedFileInfo = function(sdHash) { + lbry.getFileInfoBySdHash(sdHash, (fileInfo) => { if (fileInfo) { if (this._claimIdOwnershipCache[fileInfo.claim_id] === undefined) { lbry._updateClaimOwnershipCache(fileInfo.claim_id); } fileInfo.isMine = !!this._claimIdOwnershipCache[fileInfo.claim_id]; } - Object.keys(this._fileInfoSubscribeCallbacks[name]).forEach(function(subscribeId) { - lbry._fileInfoSubscribeCallbacks[name][subscribeId](fileInfo); + Object.keys(this._fileInfoSubscribeCallbacks[sdHash]).forEach(function(subscribeId) { + lbry._fileInfoSubscribeCallbacks[sdHash][subscribeId](fileInfo); }); }); - if (Object.keys(this._fileInfoSubscribeCallbacks[name]).length) { + if (Object.keys(this._fileInfoSubscribeCallbacks[sdHash]).length) { setTimeout(() => { - this._updateSubscribedFileInfoByName(name) + this._updateSubscribedFileInfo(sdHash) }, lbry._fileInfoSubscribeInterval); } } -lbry.fileInfoSubscribeByName = function(name, callback) { - if (!lbry._fileInfoSubscribeCallbacks[name]) +lbry.fileInfoSubscribe = function(sdHash, callback) { + if (!lbry._fileInfoSubscribeCallbacks[sdHash]) { - lbry._fileInfoSubscribeCallbacks[name] = {}; + lbry._fileInfoSubscribeCallbacks[sdHash] = {}; } const subscribeId = ++lbry._fileInfoSubscribeIdCounter; - lbry._fileInfoSubscribeCallbacks[name][subscribeId] = callback; - lbry._updateSubscribedFileInfoByName(name); + lbry._fileInfoSubscribeCallbacks[sdHash][subscribeId] = callback; + lbry._updateSubscribedFileInfo(sdHash); return subscribeId; } -// lbry.fileInfoSubscribeByStreamHash = function(sdHash, callback) { -// lbry.getFileInfoBySdHash(this.props.sdHash, this.updateFileInfoCallback); -// this.getIsMineIfNeeded(this.props.sdHash); -// setTimeout(() => { this.updateFileInfo() }, this._fileInfoCheckInterval); -// } - lbry.fileInfoUnsubscribe = function(name, subscribeId) { delete lbry._fileInfoSubscribeCallbacks[name][subscribeId]; } diff --git a/js/page/file-list.js b/js/page/file-list.js new file mode 100644 index 000000000..9b4a7674f --- /dev/null +++ b/js/page/file-list.js @@ -0,0 +1,194 @@ +import React from 'react'; +import lbry from '../lbry.js'; +import {Link} from '../component/link.js'; +import FormField from '../component/form.js'; +import {FileTileStream} from '../component/file-tile.js'; +import {BusyMessage, Thumbnail} from '../component/common.js'; + + +export let FileListDownloaded = React.createClass({ + _isMounted: false, + + getInitialState: function() { + return { + fileInfos: null, + }; + }, + componentDidMount: function() { + this._isMounted = true; + document.title = "Downloaded Files"; + + let publishedFilesSdHashes = []; + lbry.getMyClaims((claimsInfo) => { + + if (!this._isMounted) { return; } + + for (let claimInfo of claimsInfo) { + let metadata = JSON.parse(claimInfo.value); + publishedFilesSdHashes.push(metadata.sources.lbry_sd_hash); + } + + lbry.getFilesInfo((fileInfos) => { + if (!this._isMounted) { return; } + + this.setState({ + fileInfos: fileInfos.filter(({sd_hash}) => { + return publishedFilesSdHashes.indexOf(sd_hash) == -1; + }) + }); + }); + }); + }, + 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 let FileListPublished = React.createClass({ + _isMounted: false, + + getInitialState: function () { + return { + fileInfos: null, + }; + }, + componentDidMount: function () { + this._isMounted = true; + document.title = "Published Files"; + + lbry.getMyClaims((claimsInfo) => { + /** + * Build newFileInfos 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 newFileInfos = Array(claimsInfo.length), + 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) { + newFileInfos[i] = fileInfo; + } + if (claimInfoProcessedCount >= claimsInfo.length) { + /** + * newfileInfos may have gaps from claims that don't have associated files in + * lbrynet, so filter out any missing elements + */ + this.setState({ + fileInfos: newFileInfos.filter(function () { + return true + }), + }); + } + }); + } + }); + }, + 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 let FileList = React.createClass({ + _sortFunctions: { + date: function(fileInfos) { + return fileInfos.reverse(); + }, + title: function(fileInfos) { + return fileInfos.sort(function(a, b) { + return ((a.metadata ? a.metadata.title.toLowerCase() : a.name) > + (b.metadata ? b.metadata.title.toLowerCase() : b.name)); + }); + }, + filename: function(fileInfos) { + return fileInfos.sort(function(a, b) { + return (a.file_name.toLowerCase() > + b.file_name.toLowerCase()); + }); + }, + }, + propTypes: { + fileInfos: React.PropTypes.array.isRequired + }, + 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 fileInfo of fileInfosSorted) { + let {lbry_uri, sd_hash, metadata} = fileInfo; + + if (!metadata || seenUris[lbry_uri]) { + continue; + } + + seenUris[lbry_uri] = true; + content.push(); + } + + return ( +
+ + Sort by { ' ' } + + + + + + + {content} +
+ ); + } +}); \ No newline at end of file diff --git a/js/page/my_files.js b/js/page/my_files.js deleted file mode 100644 index 6571e7291..000000000 --- a/js/page/my_files.js +++ /dev/null @@ -1,196 +0,0 @@ -import React from 'react'; -import lbry from '../lbry.js'; -import {Link} from '../component/link.js'; -import FormField from '../component/form.js'; -import {FileTileStream} from '../component/file-tile.js'; -import {BusyMessage, Thumbnail} from '../component/common.js'; - -export let MyFilesPage = React.createClass({ - _fileTimeout: null, - _fileInfoCheckRate: 300, - _fileInfoCheckNum: 0, - _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()); - }); - }, - }, - - getInitialState: function() { - return { - filesInfo: null, - publishedFilesSdHashes: null, - filesAvailable: null, - sortBy: 'date', - }; - }, - getDefaultProps: function() { - return { - show: null, - }; - }, - componentDidMount: function() { - document.title = "My Files"; - }, - 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(); - }); - }, - componentWillUnmount: function() { - if (this._fileTimeout) - { - clearTimeout(this._fileTimeout); - } - }, - 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 - */ - this.setState({ - filesInfo: newFilesInfo.filter(function() { return true }), - }); - - 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) => { - 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); - }) - } - }, - render: function() { - if (this.state.filesInfo === null || (this.props.show == 'downloaded' && this.state.publishedFileSdHashes === null)) { - return ( -
- -
- ); - } else if (!this.state.filesInfo.length) { - return ( -
- {this.props.show == 'downloaded' - ? You haven't downloaded anything from LBRY yet. Go ! - : You haven't published anything to LBRY yet.} -
- ); - } else { - var content = [], - seenUris = {}; - - const filesInfoSorted = this._sortFunctions[this.state.sortBy](this.state.filesInfo); - for (let fileInfo of filesInfoSorted) { - let {lbry_uri, sd_hash, metadata} = fileInfo; - - if (!metadata || seenUris[lbry_uri]) { - continue; - } - - seenUris[lbry_uri] = true; - content.push(); - } - } - return ( -
- - Sort by { ' ' } - - - - - - - {content} -
- ); - } -}); \ No newline at end of file diff --git a/scss/_gui.scss b/scss/_gui.scss index 137c60b24..7a464a794 100644 --- a/scss/_gui.scss +++ b/scss/_gui.scss @@ -347,12 +347,6 @@ input[type="text"], input[type="search"] margin: 0px 6px; } -.error-modal__error-list { - border: 1px solid #eee; - padding: 8px; - list-style: none; -} - .error-modal-overlay { background: rgba(#000, .88); } @@ -371,12 +365,15 @@ input[type="text"], input[type="search"] word-break: break-all; } - .error-modal { max-width: none; width: 400px; } .error-modal__error-list { /*shitty hack/temp fix for long errors making modals unusable*/ + border: 1px solid #eee; + padding: 8px; + list-style: none; max-height: 400px; + max-width: 400px; overflow-y: hidden; }