Merge remote-tracking branch 'origin/master' into txlog2

This commit is contained in:
Jeremy Kauffman 2016-08-26 19:07:49 -04:00
commit f538c9a775
12 changed files with 223 additions and 85 deletions

9
dist/img/default-thumb.svg vendored Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="288">
<rect fill="#09f911" width="96" height="288"/>
<rect fill="#029d74" width="96" height="288" x="96"/>
<rect fill="#e35bd8" width="96" height="288" x="192"/>
<rect fill="#4156c5" width="96" height="288" x="288"/>
<rect fill="#635688" width="96" height="288" x="384"/>
<text font-size="32" fill="white" font-family="Bitstream Vera Sans" x="388.1" y="269.3">+<tspan font-size="48">C0</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 507 B

View file

@ -31,7 +31,7 @@ var App = React.createClass({
}
var message = 'The version of LBRY you\'re using is not up to date.\n\n' +
'Choose "OK" to download the latest version."';
'Choose "OK" to download the latest version.';
lbry.getVersionInfo(function(versionInfo) {
if (versionInfo.os_system == 'Darwin') {

View file

@ -4,6 +4,9 @@ var lbry = {
daemonConnectionString: 'http://localhost:5279/lbryapi',
colors: {
primary: '#155B4A'
},
defaultClientSettings: {
showNsfw: false,
}
};
@ -90,13 +93,20 @@ lbry.getNewAddress = function(callback) {
lbry.call('get_new_address', {}, callback);
}
lbry.getSettings = function(callback) {
lbry.getDaemonSettings = function(callback) {
lbry.call('get_settings', {}, callback);
};
}
lbry.setSettings = function(settings, callback) {
lbry.setDaemonSettings = function(settings, callback) {
lbry.call('set_settings', settings, callback);
};
}
lbry.setDaemonSetting = function(setting, value, callback) {
var setSettingsArgs = {};
setSettingsArgs[setting] = value;
lbry.call('set_settings', setSettingsArgs, callback)
}
lbry.getBalance = function(callback)
{
@ -208,6 +218,31 @@ lbry.checkNewVersionAvailable = function(callback) {
});
}
lbry.getClientSettings = function() {
var outSettings = {};
for (let setting of Object.keys(lbry.defaultClientSettings)) {
var localStorageVal = localStorage.getItem('setting_' + setting);
outSettings[setting] = (localStorageVal === null ? lbry.defaultClientSettings[setting] : JSON.parse(localStorageVal));
}
return outSettings;
}
lbry.getClientSetting = function(setting) {
var localStorageVal = localStorage.getItem('setting_' + setting);
return (localStorageVal === null ? lbry.defaultClientSettings[setting] : JSON.parse(localStorageVal));
}
lbry.setClientSettings = function(settings) {
for (let setting of Object.keys(settings)) {
lbry.setClientSetting(setting, settings[setting]);
}
}
lbry.setClientSetting = function(setting, value) {
return localStorage.setItem('setting_' + setting, JSON.stringify(value));
}
lbry.reportBug = function(message, callback) {
lbry.call('upload_log', {
name_prefix: 'report',

View file

@ -36,12 +36,11 @@ var SearchResults = React.createClass({
render: function() {
var rows = [];
this.props.results.forEach(function(result) {
if (!result.value.nsfw) {
console.log(result);
rows.push(
<SearchResultRow key={result.name} name={result.name} title={result.value.title} imgUrl={result.value.thumbnail}
description={result.value.description} cost={result.cost} />
description={result.value.description} cost={result.cost} nsfw={result.value.nsfw} />
);
}
});
return (
<div>{rows}</div>
@ -77,16 +76,27 @@ var
var SearchResultRow = React.createClass({
getInitialState: function() {
return {
downloading: false
downloading: false,
isHovered: false,
}
},
handleMouseOver: function() {
this.setState({
isHovered: true,
});
},
handleMouseOut: function() {
this.setState({
isHovered: false,
});
},
render: function() {
var obscureNsfw = !lbry.getClientSetting('showNsfw') && this.props.nsfw;
return (
<section className="card">
<div className="row-fluid" style={searchRowStyle}>
<section className={ 'card ' + (obscureNsfw ? 'card-obscured' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
<div className="row-fluid card-content" style={searchRowStyle}>
<div className="span3">
<img src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />
<img src={this.props.imgUrl || '/img/default-thumb.svg'} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />
</div>
<div className="span9">
<span style={searchRowCostStyle}>
@ -101,14 +111,27 @@ var SearchResultRow = React.createClass({
<p style={searchRowDescriptionStyle}>{this.props.description}</p>
</div>
</div>
{
!obscureNsfw || !this.state.isHovered ? null :
<div className='card-overlay'>
<p>
This content is Not Safe For Work.
To view adult content, please change your <Link href="?settings" label="Settings" />.
</p>
</div>
}
</section>
);
}
});
var featuredContentItemContainerStyle = {
position: 'relative',
};
var FeaturedContentItem = React.createClass({
resolveSearch: false,
propTypes: {
name: React.PropTypes.string,
},
@ -118,31 +141,43 @@ var FeaturedContentItem = React.createClass({
metadata: null,
title: null,
amount: 0.0,
overlayShowing: false,
};
},
componentWillMount: function() {
lbry.search(this.props.name, (results) => {
componentWillUnmount: function() {
this.resolveSearch = false;
},
componentDidMount: function() {
this.resolveSearch = true;
lbry.search(this.props.name, function(results) {
var result = results[0];
var metadata = result.value;
if (this.resolveSearch)
{
this.setState({
metadata: metadata,
amount: result.cost,
available: result.available,
title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
})
});
}
}.bind(this));
},
render: function() {
if (this.state.metadata == null) {
// Still waiting for metadata
if (this.state.metadata === null) {
// Still waiting for metadata, skip render
return null;
}
return <SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail}
description={this.state.metadata.description} cost={this.state.amount}
available={this.state.available} />;
return (<div style={featuredContentItemContainerStyle}>
<SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail || '/img/default-thumb.svg'}
description={this.state.metadata.description} cost={this.state.amount} nsfw={this.state.metadata.nsfw}
available={this.state.available} />
</div>);
}
});
@ -160,16 +195,19 @@ var FeaturedContent = React.createClass({
<h3>Featured Content</h3>
<FeaturedContentItem name="what" />
<FeaturedContentItem name="itsadisaster" />
<FeaturedContentItem name="keynesvhayek" />
<FeaturedContentItem name="meetlbry1" />
<FeaturedContentItem name="coloradobridge" />
<FeaturedContentItem name="samhyde2070" />
<FeaturedContentItem name="LendersDen" />
</div>
<div className="span6">
<h3>Community Content <ToolTipLink style={featuredContentLegendStyle} label="What's this?"
tooltip='Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three" and "four" to put your content here!' /></h3>
tooltip='Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!' /></h3>
<FeaturedContentItem name="one" />
<FeaturedContentItem name="two" />
<FeaturedContentItem name="three" />
<FeaturedContentItem name="four" />
<FeaturedContentItem name="five" />
</div>
</div>
);
@ -182,17 +220,25 @@ var DiscoverPage = React.createClass({
componentDidUpdate: function() {
if (this.props.query != this.state.query)
{
this.handleSearchChanged();
}
},
handleSearchChanged: function() {
this.setState({
searching: true,
query: this.props.query,
});
lbry.search(this.props.query, this.searchCallback);
}
},
componentDidMount: function() {
document.title = "Discover";
if (this.props.query !== '') {
// Rendering with a query already typed
this.handleSearchChanged();
}
},
getInitialState: function() {
@ -204,10 +250,6 @@ var DiscoverPage = React.createClass({
},
searchCallback: function(results) {
console.log('results:', results)
console.log('search callback');
console.log(this.state);
console.log(this.props);
if (this.state.searching) //could have canceled while results were pending, in which case nothing to do
{
this.setState({

View file

@ -15,7 +15,7 @@ var HelpPage = React.createClass({
<section className="card">
<h3>Get Live Help</h3>
<p>
Live help is available most hours in the #help channel of our Slack chat room.
Live help is available most hours in the <strong>#help</strong> channel of our Slack chat room.
</p>
<p>
<Link button="alt" label="Join Our Slack" icon="icon-slack" href="https://slack.lbry.io" />
@ -24,15 +24,17 @@ var HelpPage = React.createClass({
<section className="card">
<h3>Common Issues</h3>
<h4>Nothing seems to start downloading.</h4>
<p>If you can't download anything, including 'wonderfullife', try forwarding ports 4444 and 3333 on your firewall or router. If you can access 'wonderfullife' but not other content, it's possible the content is not longer hosted on the network.</p>
<p>If you can't download anything, including the Featured Content on the front page, your system may be unable to receive connections from other LBRY users hosting content. If you're able, try forwarding ports 4444 and 3333 on your firewall or router.</p>
<p>If only certain content is failing to download, the user(s) hosting the file may have disconnected from LBRY, or are having issues with their own connection. We are currently rolling out improvements to the network that will make content more consistently available.</p>
<h4>Videos have trouble playing.</h4>
<p>Sometimes your video player will start the file while it's still empty. Try reloading the page after a few seconds and it may work. You should also see the file appear in your downloads folder (configured in <a href="/?settings">settings</a>).</p>
<p>Sometimes the video player will start before enough of the file has downloaded to start playing. Try reloading the page after a few seconds. You should also see the file appear in your downloads folder (configured on the <Link href="/?settings" label="Settings page" />).</p>
<p>A real fix for this is underway!</p>
<h4>How do I turn LBRY off?</h4>
<p>If you're on OS X you can find the app running in the notification area at the top right of your screen. Click the LBRY icon and choose <code>Quit</code>.</p>
<p>If you're on OS X, you can find the app running in the notification area at the top right of your screen. Click the LBRY icon and choose <code>Quit</code>.</p>
<p>On Linux, you'll find a close button in the menu at the top right of LBRY.</p>

View file

@ -57,6 +57,7 @@ var moreButtonColumnStyle = {
},
artStyle = {
maxHeight: '100px',
maxWidth: '100%',
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
@ -97,7 +98,7 @@ var MyFilesRow = React.createClass({
<section className="card">
<div className="row-fluid">
<div className="span3">
{this.props.imgUrl ? <img src={this.props.imgUrl} alt={'Photo for ' + this.props.title} style={artStyle} /> : null}
<img src={this.props.imgUrl || '/img/default-thumb.svg'} alt={'Photo for ' + this.props.title} style={artStyle} />
</div>
<div className="span8">
<h3>{this.props.pending ? this.props.title : <a href={'/?show=' + this.props.lbryUri}>{this.props.title}</a>}</h3>

View file

@ -41,7 +41,16 @@ var PublishPage = React.createClass({
return;
}
var metadata = {ver: '0.0.2'};
if (this.state.nameIsMine) {
// Pre-populate with existing metadata
var metadata = Object.assign({}, this.state.claimMetadata);
if (this.refs.file.getValue() !== '') {
delete metadata.sources;
}
} else {
var metadata = {};
}
metadata['ver'] = '0.0.2';
for (let metaField of ['title', 'author', 'description', 'thumbnail', 'license', 'license_url', 'language', 'nsfw']) {
var value = this.refs['meta_' + metaField].getValue();
if (value !== '') {
@ -71,9 +80,7 @@ var PublishPage = React.createClass({
metadata: metadata,
};
if (this.refs.file.getValue() === '') {
publishArgs.metadata.sources = this.state.claimMetadata.sources;
} else {
if (this.refs.file.getValue() !== '') {
publishArgs.file_path = this._tempFilePath;
}

View file

@ -14,64 +14,60 @@ var settingsRadioOptionStyles = {
};
var SettingsPage = React.createClass({
storeSetting: function(setting, val) {
var settings = Object.assign({}, this.state.settings);
settings[setting] = val;
this.setState({
'settings': settings
});
lbry.setSettings(settings);
},
onRunOnStartChange: function (event) {
this.storeSetting('run_on_startup', event.target.checked);
lbry.setDaemonSetting('run_on_startup', event.target.checked);
},
onShareDataChange: function (event) {
this.storeSetting('upload_log', event.target.checked);
lbry.setDaemonSetting('upload_log', event.target.checked);
},
onDownloadDirChange: function(event) {
this.storeSetting('download_directory', event.target.value);
lbry.setDaemonSetting('download_directory', event.target.value);
},
onMaxUploadPrefChange: function(isLimited) {
if (!isLimited) {
this.storeSetting('max_upload', 0.0);
lbry.setDaemonSetting('max_upload', 0.0);
}
this.setState({
isMaxUpload: isLimited
});
},
onMaxUploadFieldChange: function(event) {
this.storeSetting('max_upload', Number(event.target.value));
lbry.setDaemonSetting('max_upload', Number(event.target.value));
},
onMaxDownloadPrefChange: function(isLimited) {
if (!isLimited) {
this.storeSetting('max_download', 0.0);
lbry.setDaemonSetting('max_download', 0.0);
}
this.setState({
isMaxDownload: isLimited
});
},
onMaxDownloadFieldChange: function(event) {
this.storeSetting('max_download', Number(event.target.value));
lbry.setDaemonSetting('max_download', Number(event.target.value));
},
getInitialState: function() {
return {
settings: null
settings: null,
showNsfw: lbry.getClientSetting('showNsfw')
}
},
componentDidMount: function() {
document.title = "Settings";
},
componentWillMount: function() {
lbry.getSettings(function(settings) {
lbry.getDaemonSettings(function(settings) {
this.setState({
settings: settings,
daemonSettings: settings,
isMaxUpload: settings.max_upload != 0,
isMaxDownload: settings.max_download != 0
});
}.bind(this));
},
onShowNsfwChange: function(event) {
lbry.setClientSetting('showNsfw', event.target.checked);
},
render: function() {
if (!this.state.settings) { // If the settings aren't loaded yet, don't render anything.
if (!this.state.daemonSettings) {
return null;
}
@ -80,13 +76,13 @@ var SettingsPage = React.createClass({
<section className="card">
<h3>Run on Startup</h3>
<label style={settingsCheckBoxOptionStyles}>
<input type="checkbox" onChange={this.onRunOnStartChange} defaultChecked={this.state.settings.run_on_startup} /> Run LBRY automatically when I start my computer
<input type="checkbox" onChange={this.onRunOnStartChange} defaultChecked={this.state.daemonSettings.run_on_startup} /> Run LBRY automatically when I start my computer
</label>
</section>
<section className="card">
<h3>Download Directory</h3>
<div className="help">Where would you like the files you download from LBRY to be saved?</div>
<input style={downloadDirectoryFieldStyles} type="text" name="download_directory" defaultValue={this.state.settings.download_directory} onChange={this.onDownloadDirChange}/>
<input style={downloadDirectoryFieldStyles} type="text" name="download_directory" defaultValue={this.state.daemonSettings.download_directory} onChange={this.onDownloadDirChange}/>
</section>
<section className="card">
<h3>Bandwidth Limits</h3>
@ -97,7 +93,7 @@ var SettingsPage = React.createClass({
</label>
<label style={settingsRadioOptionStyles}>
<input type="radio" name="max_upload_pref" onChange={this.onMaxUploadPrefChange.bind(this, true)} defaultChecked={this.state.isMaxUpload}/> { this.state.isMaxUpload ? 'Up to' : 'Choose limit...' }
<span className={ this.state.isMaxUpload ? '' : 'hidden'}> <input type="number" min="0" step=".5" defaultValue={this.state.settings.max_upload} style={settingsNumberFieldStyles} onChange={this.onMaxUploadFieldChange}/> MB/s</span>
<span className={ this.state.isMaxUpload ? '' : 'hidden'}> <input type="number" min="0" step=".5" defaultValue={this.state.daemonSettings.max_upload} style={settingsNumberFieldStyles} onChange={this.onMaxUploadFieldChange}/> MB/s</span>
</label>
</div>
<div className="form-row">
@ -107,14 +103,26 @@ var SettingsPage = React.createClass({
</label>
<label style={settingsRadioOptionStyles}>
<input type="radio" name="max_download_pref" onChange={this.onMaxDownloadPrefChange.bind(this, true)} defaultChecked={this.state.isMaxDownload}/> { this.state.isMaxDownload ? 'Up to' : 'Choose limit...' }
<span className={ this.state.isMaxDownload ? '' : 'hidden'}> <input type="number" min="0" step=".5" defaultValue={this.state.settings.max_download} style={settingsNumberFieldStyles} onChange={this.onMaxDownloadFieldChange}/> MB/s</span>
<span className={ this.state.isMaxDownload ? '' : 'hidden'}> <input type="number" min="0" step=".5" defaultValue={this.state.daemonSettings.max_download} style={settingsNumberFieldStyles} onChange={this.onMaxDownloadFieldChange}/> MB/s</span>
</label>
</div>
</section>
<section className="card">
<h3>Content</h3>
<div className="form-row">
<label style={settingsCheckBoxOptionStyles}>
<input type="checkbox" onChange={this.onShowNsfwChange} defaultChecked={this.state.showNsfw} /> Show NSFW Content
</label>
<div className="help">
NSFW content may include nudity, intense sexuality, profanity, or other adult content.
By displaying NSFW content, you are affirming you are of legal age to view mature content in your country or jurisdiction.
</div>
</div>
</section>
<section className="card">
<h3>Share Diagnostic Data</h3>
<label style={settingsCheckBoxOptionStyles}>
<input type="checkbox" onChange={this.onShareDataChange} defaultChecked={this.state.settings.upload_log} /> Help make LBRY better by contributing diagnostic data about my usage
<input type="checkbox" onChange={this.onShareDataChange} defaultChecked={this.state.daemonSettings.upload_log} /> Help make LBRY better by contributing diagnostic data about my usage
</label>
</section>
</main>

View file

@ -12,6 +12,7 @@ var FormatItem = React.createClass({
claimInfo: React.PropTypes.object,
amount: React.PropTypes.number,
name: React.PropTypes.string,
available: React.PropTypes.string,
},
render: function() {
@ -24,12 +25,13 @@ var FormatItem = React.createClass({
var license = claimInfo.license;
var fileContentType = claimInfo['content-type'];
var available = this.props.available;
var amount = this.props.amount || 0.0;
return (
<div className="row-fluid">
<div className="span4">
<img src={thumbnail} alt={'Photo for ' + title} style={formatItemImgStyle} />
<img src={thumbnail || '/img/default-thumb.svg'} alt={'Photo for ' + title} style={formatItemImgStyle} />
</div>
<div className="span8">
<p>{description}</p>
@ -39,7 +41,7 @@ var FormatItem = React.createClass({
<td>Content-Type</td><td>{fileContentType}</td>
</tr>
<tr>
<td>Cost</td><td><CreditAmount amount={amount} isEstimate={true}/></td>
<td>Cost</td><td><CreditAmount amount={amount} isEstimate={!available}/></td>
</tr>
<tr>
<td>Author</td><td>{author}</td>
@ -65,6 +67,7 @@ var FormatsSection = React.createClass({
claimInfo: React.PropTypes.object,
amount: React.PropTypes.number,
name: React.PropTypes.string,
available: React.PropTypes.string,
},
render: function() {
var name = this.props.name;
@ -86,7 +89,7 @@ var FormatsSection = React.createClass({
{/* In future, anticipate multiple formats, just a guess at what it could look like
// var formats = this.props.claimInfo.formats
// return (<tbody>{formats.map(function(format,i){ */}
<FormatItem claimInfo={format} amount={this.props.amount} />
<FormatItem claimInfo={format} amount={this.props.amount} name={this.props.name} available={this.props.available} />
{/* })}</tbody>); */}
</div>);
}
@ -109,7 +112,8 @@ var DetailPage = React.createClass({
lbry.search(this.props.name, (results) => {
var result = results[0];
this.setState({
amount: result.amount,
amount: result.cost,
available: result.available,
claimInfo: result.value,
searching: false,
});
@ -122,13 +126,14 @@ var DetailPage = React.createClass({
}
var name = this.props.name;
var available = this.state.available;
var claimInfo = this.state.claimInfo;
var amount = this.state.amount;
return (
<main>
<section className="card">
<FormatsSection name={name} claimInfo={claimInfo} amount={amount} />
<FormatsSection name={name} claimInfo={claimInfo} amount={amount} available={available} />
</section>
</main>);
}

View file

@ -157,6 +157,30 @@ $header-icon-size: 1.5em;
box-shadow: $default-box-shadow;
border-radius: 2px;
}
.card-obscured
{
position: relative;
}
.card-obscured .card-content {
-webkit-filter: blur($blur-intensity);
-moz-filter: blur($blur-intensity);
-o-filter: blur($blur-intensity);
-ms-filter: blur($blur-intensity);
filter: blur($blur-intensity);
}
.card-overlay {
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
padding: 20px;
background-color: rgba(128, 128, 128, 0.8);
color: #fff;
display: flex;
align-items: center;
font-weight: 600;
}
.card-series-submit
{

View file

@ -21,6 +21,7 @@ $header-height: $spacing-vertical * 2.5;
$default-box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
$blur-intensity: 8px;
@mixin clearfix()
{

View file

@ -17,6 +17,10 @@ section
{
margin-bottom: 0;
}
&:only-child {
/* If it's an only child, assume it's part of a React layout that will handle the last child condition on its own */
margin-bottom: $spacing-vertical;
}
}
main h1 {