Actually hide NSFW content #1748
4 changed files with 50 additions and 85 deletions
|
@ -4,46 +4,20 @@ import classnames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
thumbnail: ?string, // externally sourced image
|
thumbnail: ?string, // externally sourced image
|
||||||
nsfw: ?boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const autoThumbColors = [
|
|
||||||
'purple',
|
|
||||||
'red',
|
|
||||||
'pink',
|
|
||||||
'indigo',
|
|
||||||
'blue',
|
|
||||||
'light-blue',
|
|
||||||
'cyan',
|
|
||||||
'teal',
|
|
||||||
'green',
|
|
||||||
'yellow',
|
|
||||||
'orange',
|
|
||||||
];
|
|
||||||
|
|
||||||
class CardMedia extends React.PureComponent<Props> {
|
class CardMedia extends React.PureComponent<Props> {
|
||||||
getAutoThumbClass = () => autoThumbColors[Math.floor(Math.random() * autoThumbColors.length)];
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { thumbnail, nsfw } = this.props;
|
const { thumbnail } = this.props;
|
||||||
|
|
||||||
const generateAutothumb = !thumbnail && !nsfw;
|
|
||||||
let autoThumbClass;
|
|
||||||
if (generateAutothumb) {
|
|
||||||
autoThumbClass = `card__media--autothumb.${this.getAutoThumbClass()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={thumbnail && !nsfw ? { backgroundImage: `url('${thumbnail}')` } : {}}
|
style={thumbnail ? { backgroundImage: `url('${thumbnail}')` } : {}}
|
||||||
className={classnames('card__media', autoThumbClass, {
|
className={classnames('card__media', {
|
||||||
'card__media--no-img': !thumbnail || nsfw,
|
'card__media--no-img': !thumbnail,
|
||||||
'card__media--nsfw': nsfw,
|
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{(!thumbnail || nsfw) && (
|
{!thumbnail && <span className="card__media-text">LBRY</span>}
|
||||||
<span className="card__media-text">{nsfw ? __('NSFW') : 'LBRY'}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
||||||
import Button from 'component/button';
|
import type { Claim, Metadata } from 'types/claim';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
@ -14,9 +14,9 @@ import { openCopyLinkMenu } from '../../util/contextMenu';
|
||||||
// TODO: iron these out
|
// TODO: iron these out
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
claim: ?{ claim_id: string },
|
claim: ?Claim,
|
||||||
fileInfo: ?{},
|
fileInfo: ?{},
|
||||||
metadata: ?{ nsfw: boolean, title: string, thumbnail: ?string },
|
metadata: ?Metadata,
|
||||||
navigate: (string, ?{}) => void,
|
navigate: (string, ?{}) => void,
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
|
@ -62,10 +62,15 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
showPrice,
|
showPrice,
|
||||||
pending,
|
pending,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const shouldHide = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
||||||
|
if (shouldHide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const uri = !pending ? normalizeURI(this.props.uri) : this.props.uri;
|
const uri = !pending ? normalizeURI(this.props.uri) : this.props.uri;
|
||||||
const title = metadata && metadata.title ? metadata.title : uri;
|
const title = metadata && metadata.title ? metadata.title : uri;
|
||||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
const handleContextMenu = event => {
|
const handleContextMenu = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -86,46 +91,26 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
})}
|
})}
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
>
|
>
|
||||||
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
<CardMedia thumbnail={thumbnail} />
|
||||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
||||||
|
<div className="card__title-identity">
|
||||||
{shouldObscureNsfw ? (
|
<div className="card__title--small">
|
||||||
<div className="card__title-identity">
|
<TruncatedText lines={3}>{title}</TruncatedText>
|
||||||
<div className="card__title--small">
|
|
||||||
<TruncatedText lines={3}>
|
|
||||||
{__('This content is obscured because it is NSFW. You can change this in ')}
|
|
||||||
<Button
|
|
||||||
button="link"
|
|
||||||
label={__('Settings.')}
|
|
||||||
onClick={e => {
|
|
||||||
// Don't propagate to the onClick handler of parent element
|
|
||||||
e.stopPropagation();
|
|
||||||
navigate('/settings');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</TruncatedText>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
<div className="card__subtitle">
|
||||||
<div className="card__title-identity">
|
{pending ? (
|
||||||
<div className="card__title--small">
|
<div>Pending...</div>
|
||||||
<TruncatedText lines={3}>{title}</TruncatedText>
|
) : (
|
||||||
</div>
|
<React.Fragment>
|
||||||
<div className="card__subtitle">
|
<UriIndicator uri={uri} link />
|
||||||
{pending ? (
|
<div>
|
||||||
<div>Pending...</div>
|
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||||
) : (
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
<React.Fragment>
|
</div>
|
||||||
<UriIndicator uri={uri} link />
|
</React.Fragment>
|
||||||
<div>
|
)}
|
||||||
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
|
||||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
/* eslint-enable jsx-a11y/click-events-have-key-events */
|
/* eslint-enable jsx-a11y/click-events-have-key-events */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
import type { Claim, Metadata } from 'types/claim';
|
||||||
import { normalizeURI, parseURI } from 'lbry-redux';
|
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
|
@ -19,15 +20,8 @@ type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
claim: ?{
|
claim: ?Claim,
|
||||||
name: string,
|
metadata: ?Metadata,
|
||||||
channel_name: string,
|
|
||||||
claim_id: string,
|
|
||||||
},
|
|
||||||
metadata: ?{
|
|
||||||
title: ?string,
|
|
||||||
thumbnail: ?string,
|
|
||||||
},
|
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
navigate: (string, ?{}) => void,
|
navigate: (string, ?{}) => void,
|
||||||
clearPublish: () => void,
|
clearPublish: () => void,
|
||||||
|
@ -70,6 +64,11 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
hideNoResult,
|
hideNoResult,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const shouldHide = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
||||||
|
if (shouldHide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const uri = normalizeURI(this.props.uri);
|
const uri = normalizeURI(this.props.uri);
|
||||||
const isClaimed = !!claim;
|
const isClaimed = !!claim;
|
||||||
const description = isClaimed && metadata && metadata.description ? metadata.description : '';
|
const description = isClaimed && metadata && metadata.description ? metadata.description : '';
|
||||||
|
@ -77,8 +76,6 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
|
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
|
||||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw && !claimIsMine;
|
|
||||||
|
|
||||||
const onClick = () => navigate('/show', { uri });
|
const onClick = () => navigate('/show', { uri });
|
||||||
|
|
||||||
let name;
|
let name;
|
||||||
|
@ -98,7 +95,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
>
|
>
|
||||||
<CardMedia title={title || name} thumbnail={thumbnail} nsfw={shouldObscureNsfw} />
|
<CardMedia title={title || name} thumbnail={thumbnail} />
|
||||||
<div className="file-tile__info">
|
<div className="file-tile__info">
|
||||||
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
|
{isResolvingUri && <div className="card__title--small">{__('Loading...')}</div>}
|
||||||
{!isResolvingUri && (
|
{!isResolvingUri && (
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
// Currently incomplete
|
||||||
|
export type Metadata = {
|
||||||
|
nsfw: boolean,
|
||||||
|
title: string,
|
||||||
|
thumbnail: ?string,
|
||||||
|
description: ?string,
|
||||||
|
};
|
||||||
|
|
||||||
// Actual claim type has more values than this
|
// Actual claim type has more values than this
|
||||||
// Add them as they are used
|
// Add them as they are used
|
||||||
export type Claim = {
|
export type Claim = {
|
||||||
|
@ -22,9 +30,10 @@ export type Claim = {
|
||||||
nout: number,
|
nout: number,
|
||||||
signature_is_valid: boolean,
|
signature_is_valid: boolean,
|
||||||
valid_at_height: number,
|
valid_at_height: number,
|
||||||
value: {
|
value: ?{
|
||||||
publisherSignature: ?{
|
publisherSignature: ?{
|
||||||
certificateId: ?string,
|
certificateId: ?string,
|
||||||
},
|
},
|
||||||
|
stream: ?Metadata,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue