Merge pull request #38 from lbryio/blur-nsfw

Blur NSFW stuff on home page (WIP)
This commit is contained in:
Jeremy Kauffman 2016-08-22 16:58:01 -04:00 committed by GitHub
commit 71719d02f4
6 changed files with 173 additions and 65 deletions

View file

@ -4,6 +4,9 @@ var lbry = {
daemonConnectionString: 'http://localhost:5279/lbryapi', daemonConnectionString: 'http://localhost:5279/lbryapi',
colors: { colors: {
primary: '#155B4A' primary: '#155B4A'
},
defaultClientSettings: {
showNsfw: false,
} }
}; };
@ -90,13 +93,20 @@ lbry.getNewAddress = function(callback) {
lbry.call('get_new_address', {}, callback); lbry.call('get_new_address', {}, callback);
} }
lbry.getSettings = function(callback) { lbry.getDaemonSettings = function(callback) {
lbry.call('get_settings', {}, callback); lbry.call('get_settings', {}, callback);
}; }
lbry.setSettings = function(settings, callback) { lbry.setDaemonSettings = function(settings, callback) {
lbry.call('set_settings', 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) 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.reportBug = function(message, callback) {
lbry.call('upload_log', { lbry.call('upload_log', {
name_prefix: 'report', name_prefix: 'report',

View file

@ -36,12 +36,11 @@ var SearchResults = React.createClass({
render: function() { render: function() {
var rows = []; var rows = [];
this.props.results.forEach(function(result) { this.props.results.forEach(function(result) {
if (!result.value.nsfw) { console.log(result);
rows.push( rows.push(
<SearchResultRow key={result.name} name={result.name} title={result.value.title} imgUrl={result.value.thumbnail} <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 ( return (
<div>{rows}</div> <div>{rows}</div>
@ -77,14 +76,25 @@ var
var SearchResultRow = React.createClass({ var SearchResultRow = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
downloading: false downloading: false,
isHovered: false,
} }
}, },
handleMouseOver: function() {
this.setState({
isHovered: true,
});
},
handleMouseOut: function() {
this.setState({
isHovered: false,
});
},
render: function() { render: function() {
var obscureNsfw = !lbry.getClientSetting('showNsfw') && this.props.nsfw;
return ( return (
<section className={ 'card ' + (obscureNsfw ? 'card-obscured' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
<section className="card"> <div className="row-fluid card-content" style={searchRowStyle}>
<div className="row-fluid" style={searchRowStyle}>
<div className="span3"> <div className="span3">
<img src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} /> <img src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} />
</div> </div>
@ -101,14 +111,27 @@ var SearchResultRow = React.createClass({
<p style={searchRowDescriptionStyle}>{this.props.description}</p> <p style={searchRowDescriptionStyle}>{this.props.description}</p>
</div> </div>
</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> </section>
); );
} }
}); });
var featuredContentItemContainerStyle = {
position: 'relative',
};
var FeaturedContentItem = React.createClass({ var FeaturedContentItem = React.createClass({
resolveSearch: false,
propTypes: { propTypes: {
name: React.PropTypes.string, name: React.PropTypes.string,
}, },
@ -118,31 +141,43 @@ var FeaturedContentItem = React.createClass({
metadata: null, metadata: null,
title: null, title: null,
amount: 0.0, amount: 0.0,
overlayShowing: false,
}; };
}, },
componentWillMount: function() { componentWillUnmount: function() {
lbry.search(this.props.name, (results) => { this.resolveSearch = false;
},
componentDidMount: function() {
this.resolveSearch = true;
lbry.search(this.props.name, function(results) {
var result = results[0]; var result = results[0];
var metadata = result.value; var metadata = result.value;
this.setState({ if (this.resolveSearch)
metadata: metadata, {
amount: result.cost, this.setState({
available: result.available, metadata: metadata,
title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name), amount: result.cost,
}) available: result.available,
}); title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
});
}
}.bind(this));
}, },
render: function() { render: function() {
if (this.state.metadata == null) { if (this.state.metadata === null) {
// Still waiting for metadata // Still waiting for metadata, skip render
return null; return null;
} }
return <SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail} return (<div style={featuredContentItemContainerStyle}>
description={this.state.metadata.description} cost={this.state.amount} <SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail}
available={this.state.available} />; description={this.state.metadata.description} cost={this.state.amount} nsfw={this.state.metadata.nsfw}
available={this.state.available} />
</div>);
} }
}); });
@ -182,17 +217,25 @@ var DiscoverPage = React.createClass({
componentDidUpdate: function() { componentDidUpdate: function() {
if (this.props.query != this.state.query) if (this.props.query != this.state.query)
{ {
this.setState({ this.handleSearchChanged();
searching: true,
query: this.props.query,
});
lbry.search(this.props.query, this.searchCallback);
} }
}, },
handleSearchChanged: function() {
this.setState({
searching: true,
query: this.props.query,
});
lbry.search(this.props.query, this.searchCallback);
},
componentDidMount: function() { componentDidMount: function() {
document.title = "Discover"; document.title = "Discover";
if (this.props.query !== '') {
// Rendering with a query already typed
this.handleSearchChanged();
}
}, },
getInitialState: function() { getInitialState: function() {
@ -204,10 +247,6 @@ var DiscoverPage = React.createClass({
}, },
searchCallback: function(results) { 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 if (this.state.searching) //could have canceled while results were pending, in which case nothing to do
{ {
this.setState({ this.setState({
@ -227,4 +266,4 @@ var DiscoverPage = React.createClass({
</main> </main>
); );
} }
}); });

View file

@ -14,64 +14,60 @@ var settingsRadioOptionStyles = {
}; };
var SettingsPage = React.createClass({ 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) { onRunOnStartChange: function (event) {
this.storeSetting('run_on_startup', event.target.checked); lbry.setDaemonSetting('run_on_startup', event.target.checked);
}, },
onShareDataChange: function (event) { onShareDataChange: function (event) {
this.storeSetting('upload_log', event.target.checked); lbry.setDaemonSetting('upload_log', event.target.checked);
}, },
onDownloadDirChange: function(event) { onDownloadDirChange: function(event) {
this.storeSetting('download_directory', event.target.value); lbry.setDaemonSetting('download_directory', event.target.value);
}, },
onMaxUploadPrefChange: function(isLimited) { onMaxUploadPrefChange: function(isLimited) {
if (!isLimited) { if (!isLimited) {
this.storeSetting('max_upload', 0.0); lbry.setDaemonSetting('max_upload', 0.0);
} }
this.setState({ this.setState({
isMaxUpload: isLimited isMaxUpload: isLimited
}); });
}, },
onMaxUploadFieldChange: function(event) { onMaxUploadFieldChange: function(event) {
this.storeSetting('max_upload', Number(event.target.value)); lbry.setDaemonSetting('max_upload', Number(event.target.value));
}, },
onMaxDownloadPrefChange: function(isLimited) { onMaxDownloadPrefChange: function(isLimited) {
if (!isLimited) { if (!isLimited) {
this.storeSetting('max_download', 0.0); lbry.setDaemonSetting('max_download', 0.0);
} }
this.setState({ this.setState({
isMaxDownload: isLimited isMaxDownload: isLimited
}); });
}, },
onMaxDownloadFieldChange: function(event) { onMaxDownloadFieldChange: function(event) {
this.storeSetting('max_download', Number(event.target.value)); lbry.setDaemonSetting('max_download', Number(event.target.value));
}, },
getInitialState: function() { getInitialState: function() {
return { return {
settings: null settings: null,
showNsfw: lbry.getClientSetting('showNsfw')
} }
}, },
componentDidMount: function() { componentDidMount: function() {
document.title = "Settings"; document.title = "Settings";
}, },
componentWillMount: function() { componentWillMount: function() {
lbry.getSettings(function(settings) { lbry.getDaemonSettings(function(settings) {
this.setState({ this.setState({
settings: settings, daemonSettings: settings,
isMaxUpload: settings.max_upload != 0, isMaxUpload: settings.max_upload != 0,
isMaxDownload: settings.max_download != 0 isMaxDownload: settings.max_download != 0
}); });
}.bind(this)); }.bind(this));
}, },
onShowNsfwChange: function(event) {
lbry.setClientSetting('showNsfw', event.target.checked);
},
render: function() { render: function() {
if (!this.state.settings) { // If the settings aren't loaded yet, don't render anything. if (!this.state.daemonSettings) {
return null; return null;
} }
@ -80,13 +76,13 @@ var SettingsPage = React.createClass({
<section className="card"> <section className="card">
<h3>Run on Startup</h3> <h3>Run on Startup</h3>
<label style={settingsCheckBoxOptionStyles}> <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> </label>
</section> </section>
<section className="card"> <section className="card">
<h3>Download Directory</h3> <h3>Download Directory</h3>
<div className="help">Where would you like the files you download from LBRY to be saved?</div> <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>
<section className="card"> <section className="card">
<h3>Bandwidth Limits</h3> <h3>Bandwidth Limits</h3>
@ -97,7 +93,7 @@ var SettingsPage = React.createClass({
</label> </label>
<label style={settingsRadioOptionStyles}> <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...' } <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> </label>
</div> </div>
<div className="form-row"> <div className="form-row">
@ -107,17 +103,26 @@ var SettingsPage = React.createClass({
</label> </label>
<label style={settingsRadioOptionStyles}> <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...' } <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> </label>
</div> </div>
</section> </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.</div>
</div>
</section>
<section className="card"> <section className="card">
<h3>Share Diagnostic Data</h3> <h3>Share Diagnostic Data</h3>
<label style={settingsCheckBoxOptionStyles}> <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> </label>
</section> </section>
</main> </main>
); );
} }
}); });

View file

@ -157,6 +157,30 @@ $header-icon-size: 1.5em;
box-shadow: $default-box-shadow; box-shadow: $default-box-shadow;
border-radius: 2px; 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 .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); $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() @mixin clearfix()
{ {

View file

@ -17,6 +17,10 @@ section
{ {
margin-bottom: 0; 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 { main h1 {