2018-03-26 23:32:43 +02:00
|
|
|
// @flow
|
2018-10-19 22:38:07 +02:00
|
|
|
import type { Claim, Metadata } from 'types/claim';
|
|
|
|
import type { FileInfo } from 'types/file_info';
|
2018-11-26 02:21:25 +01:00
|
|
|
import * as MODALS from 'constants/modal_types';
|
2018-12-19 06:44:53 +01:00
|
|
|
import * as icons from 'constants/icons';
|
2018-03-26 23:32:43 +02:00
|
|
|
import * as React from 'react';
|
2018-10-29 18:23:53 +01:00
|
|
|
import { buildURI, normalizeURI } from 'lbry-redux';
|
2018-07-10 05:32:59 +02:00
|
|
|
import FileViewer from 'component/fileViewer';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Thumbnail from 'component/common/thumbnail';
|
2017-12-21 22:08:54 +01:00
|
|
|
import FilePrice from 'component/filePrice';
|
|
|
|
import FileDetails from 'component/fileDetails';
|
2018-03-26 23:32:43 +02:00
|
|
|
import FileActions from 'component/fileActions';
|
2017-12-21 22:08:54 +01:00
|
|
|
import UriIndicator from 'component/uriIndicator';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Icon from 'component/common/icon';
|
2017-12-21 22:08:54 +01:00
|
|
|
import DateTime from 'component/dateTime';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Button from 'component/button';
|
2017-12-21 22:08:54 +01:00
|
|
|
import SubscribeButton from 'component/subscribeButton';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Page from 'component/page';
|
2018-05-21 22:30:00 +02:00
|
|
|
import FileDownloadLink from 'component/fileDownloadLink';
|
2018-06-13 22:32:38 +02:00
|
|
|
import classnames from 'classnames';
|
2018-11-21 22:20:55 +01:00
|
|
|
import getMediaType from 'util/get-media-type';
|
2018-07-25 06:45:24 +02:00
|
|
|
import RecommendedContent from 'component/recommendedContent';
|
2017-09-12 06:24:04 +02:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
type Props = {
|
2018-05-07 06:50:55 +02:00
|
|
|
claim: Claim,
|
2018-10-19 22:38:07 +02:00
|
|
|
fileInfo: FileInfo,
|
|
|
|
metadata: Metadata,
|
2018-03-26 23:32:43 +02:00
|
|
|
contentType: string,
|
|
|
|
uri: string,
|
|
|
|
rewardedContentClaimIds: Array<string>,
|
|
|
|
obscureNsfw: boolean,
|
|
|
|
claimIsMine: boolean,
|
2018-10-19 22:38:07 +02:00
|
|
|
costInfo: ?{ cost: number },
|
2018-03-26 23:32:43 +02:00
|
|
|
fetchFileInfo: string => void,
|
|
|
|
fetchCostInfo: string => void,
|
2018-10-10 07:22:06 +02:00
|
|
|
setViewed: string => void,
|
2018-10-19 22:38:07 +02:00
|
|
|
isSubscribed: ?string,
|
|
|
|
isSubscribed: boolean,
|
|
|
|
channelUri: string,
|
2019-03-14 19:40:26 +01:00
|
|
|
viewCount: number,
|
2018-10-19 22:38:07 +02:00
|
|
|
prepareEdit: ({}, string) => void,
|
|
|
|
navigate: (string, ?{}) => void,
|
2018-10-29 18:23:53 +01:00
|
|
|
openModal: (id: string, { uri: string }) => void,
|
2018-10-19 22:38:07 +02:00
|
|
|
markSubscriptionRead: (string, string) => void,
|
2019-03-14 19:40:26 +01:00
|
|
|
fetchViewCount: string => void,
|
2018-03-26 23:32:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class FilePage extends React.Component<Props> {
|
2018-06-18 20:18:25 +02:00
|
|
|
static PLAYABLE_MEDIA_TYPES = ['audio', 'video'];
|
2018-07-05 07:24:04 +02:00
|
|
|
static PREVIEW_MEDIA_TYPES = [
|
|
|
|
'text',
|
|
|
|
'model',
|
|
|
|
'image',
|
2018-08-02 06:56:17 +02:00
|
|
|
'script',
|
2018-07-05 07:24:04 +02:00
|
|
|
'document',
|
2018-08-02 06:56:17 +02:00
|
|
|
'3D-file',
|
2018-07-05 07:24:04 +02:00
|
|
|
// Bypass unplayable files
|
|
|
|
// TODO: Find a better way to detect supported types
|
|
|
|
'application',
|
|
|
|
];
|
2018-06-11 08:41:25 +02:00
|
|
|
|
2017-05-13 00:50:51 +02:00
|
|
|
componentDidMount() {
|
2019-03-14 19:40:26 +01:00
|
|
|
const {
|
|
|
|
uri,
|
|
|
|
fetchFileInfo,
|
|
|
|
fetchCostInfo,
|
|
|
|
setViewed,
|
|
|
|
isSubscribed,
|
|
|
|
claimIsMine,
|
|
|
|
fetchViewCount,
|
|
|
|
claim,
|
|
|
|
} = this.props;
|
2018-10-19 22:38:07 +02:00
|
|
|
|
|
|
|
if (isSubscribed) {
|
|
|
|
this.removeFromSubscriptionNotifications();
|
|
|
|
}
|
2019-03-14 19:40:26 +01:00
|
|
|
|
|
|
|
if (claimIsMine) {
|
|
|
|
fetchViewCount(claim.claim_id);
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:26:50 +01:00
|
|
|
// always refresh file info when entering file page
|
|
|
|
fetchFileInfo(uri);
|
2017-05-12 19:14:06 +02:00
|
|
|
|
2018-07-12 20:39:12 +02:00
|
|
|
// See https://github.com/lbryio/lbry-desktop/pull/1563 for discussion
|
2018-06-07 19:47:09 +02:00
|
|
|
fetchCostInfo(uri);
|
2018-07-31 20:07:45 +02:00
|
|
|
setViewed(uri);
|
2017-05-12 19:14:06 +02:00
|
|
|
}
|
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
componentWillReceiveProps(nextProps: Props) {
|
2018-08-31 05:45:49 +02:00
|
|
|
const { fetchFileInfo, uri, setViewed } = this.props;
|
2018-03-26 23:32:43 +02:00
|
|
|
if (nextProps.fileInfo === undefined) {
|
|
|
|
fetchFileInfo(uri);
|
2017-05-26 20:17:01 +02:00
|
|
|
}
|
2018-08-31 05:45:49 +02:00
|
|
|
|
2018-08-30 07:11:05 +02:00
|
|
|
if (uri !== nextProps.uri) {
|
|
|
|
setViewed(nextProps.uri);
|
|
|
|
}
|
2017-05-26 20:17:01 +02:00
|
|
|
}
|
|
|
|
|
2018-10-19 22:38:07 +02:00
|
|
|
componentDidUpdate(prevProps: Props) {
|
2019-03-14 19:40:26 +01:00
|
|
|
const { isSubscribed, claim, uri, fetchViewCount } = this.props;
|
|
|
|
|
|
|
|
if (!prevProps.isSubscribed && isSubscribed) {
|
2018-10-19 22:38:07 +02:00
|
|
|
this.removeFromSubscriptionNotifications();
|
|
|
|
}
|
2019-03-14 19:40:26 +01:00
|
|
|
|
|
|
|
if (prevProps.uri !== uri) {
|
|
|
|
fetchViewCount(claim.claim_id);
|
|
|
|
}
|
2018-10-19 22:38:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
removeFromSubscriptionNotifications() {
|
|
|
|
// Always try to remove
|
|
|
|
// If it doesn't exist, nothing will happen
|
|
|
|
const { markSubscriptionRead, uri, channelUri } = this.props;
|
|
|
|
markSubscriptionRead(channelUri, uri);
|
|
|
|
}
|
2018-03-06 09:32:58 +01:00
|
|
|
|
2017-05-12 19:14:06 +02:00
|
|
|
render() {
|
2017-07-25 09:07:54 +02:00
|
|
|
const {
|
|
|
|
claim,
|
|
|
|
metadata,
|
|
|
|
contentType,
|
|
|
|
uri,
|
2017-07-30 00:56:08 +02:00
|
|
|
rewardedContentClaimIds,
|
2018-03-26 23:32:43 +02:00
|
|
|
obscureNsfw,
|
|
|
|
openModal,
|
|
|
|
claimIsMine,
|
|
|
|
prepareEdit,
|
|
|
|
navigate,
|
2018-03-30 18:13:11 +02:00
|
|
|
costInfo,
|
2018-07-05 04:49:12 +02:00
|
|
|
fileInfo,
|
2018-10-19 22:38:07 +02:00
|
|
|
channelUri,
|
2019-03-14 19:40:26 +01:00
|
|
|
viewCount,
|
2017-07-25 09:07:54 +02:00
|
|
|
} = this.props;
|
2017-05-01 22:50:07 +02:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
// File info
|
2018-07-05 04:49:12 +02:00
|
|
|
const { title, thumbnail } = metadata;
|
2018-10-19 22:38:07 +02:00
|
|
|
const { height, channel_name: channelName } = claim;
|
2018-06-18 20:18:25 +02:00
|
|
|
const { PLAYABLE_MEDIA_TYPES, PREVIEW_MEDIA_TYPES } = FilePage;
|
2018-07-31 20:07:45 +02:00
|
|
|
const isRewardContent = (rewardedContentClaimIds || []).includes(claim.claim_id);
|
2018-03-26 23:32:43 +02:00
|
|
|
const shouldObscureThumbnail = obscureNsfw && metadata.nsfw;
|
2018-07-05 04:49:12 +02:00
|
|
|
const fileName = fileInfo ? fileInfo.file_name : null;
|
2018-07-10 04:57:34 +02:00
|
|
|
const mediaType = getMediaType(contentType, fileName);
|
2018-06-18 20:18:25 +02:00
|
|
|
const showFile =
|
|
|
|
PLAYABLE_MEDIA_TYPES.includes(mediaType) || PREVIEW_MEDIA_TYPES.includes(mediaType);
|
2018-10-04 15:39:14 +02:00
|
|
|
const speechShareable =
|
2018-03-30 18:13:11 +02:00
|
|
|
costInfo &&
|
|
|
|
costInfo.cost === 0 &&
|
|
|
|
contentType &&
|
|
|
|
['video', 'image'].includes(contentType.split('/')[0]);
|
2018-05-23 06:35:34 +02:00
|
|
|
// We want to use the short form uri for editing
|
|
|
|
// This is what the user is used to seeing, they don't care about the claim id
|
|
|
|
// We will select the claim id before they publish
|
|
|
|
let editUri;
|
|
|
|
if (claimIsMine) {
|
2019-01-19 19:54:06 +01:00
|
|
|
const uriObject: { contentName: string, claimId: string, channelName?: string } = {
|
2018-10-19 22:38:07 +02:00
|
|
|
contentName: claim.name,
|
|
|
|
claimId: claim.claim_id,
|
|
|
|
};
|
2018-06-12 07:11:17 +02:00
|
|
|
if (channelName) {
|
|
|
|
uriObject.channelName = channelName;
|
|
|
|
}
|
|
|
|
|
|
|
|
editUri = buildURI(uriObject);
|
2018-05-23 06:35:34 +02:00
|
|
|
}
|
|
|
|
|
2017-05-12 19:14:06 +02:00
|
|
|
return (
|
2019-01-09 19:39:05 +01:00
|
|
|
<Page notContained className="main--file-page">
|
|
|
|
<div className="grid-area--content">
|
|
|
|
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
|
|
|
|
{!showFile &&
|
|
|
|
(thumbnail ? (
|
|
|
|
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
|
|
|
) : (
|
|
|
|
<div
|
|
|
|
className={classnames('content__empty', {
|
|
|
|
'content__empty--nsfw': shouldObscureThumbnail,
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
<div className="card__media-text">
|
|
|
|
{__("Sorry, looks like we can't preview this file.")}
|
|
|
|
</div>
|
2017-10-10 06:53:50 +02:00
|
|
|
</div>
|
2019-01-09 19:39:05 +01:00
|
|
|
))}
|
|
|
|
</div>
|
2018-07-25 02:50:04 +02:00
|
|
|
|
2019-01-09 19:39:05 +01:00
|
|
|
<div className="grid-area--info media__content media__content--large">
|
2018-12-19 06:44:53 +01:00
|
|
|
<h1 className="media__title media__title--large">{title}</h1>
|
|
|
|
|
|
|
|
<div className="media__properties media__properties--large">
|
|
|
|
{isRewardContent && (
|
2019-02-05 18:03:18 +01:00
|
|
|
<Icon
|
|
|
|
size={20}
|
|
|
|
iconColor="red"
|
|
|
|
icon={icons.FEATURED}
|
|
|
|
// Figure out how to get the tooltip to overlap the navbar on the file page and I will love you
|
|
|
|
// https://stackoverflow.com/questions/6421966/css-overflow-x-visible-and-overflow-y-hidden-causing-scrollbar-issue
|
|
|
|
// https://spee.ch/4/overflow-issue
|
|
|
|
// tooltip="bottom"
|
|
|
|
/>
|
2018-12-19 06:44:53 +01:00
|
|
|
)}
|
|
|
|
{metadata.nsfw && <div className="badge badge--nsfw">NSFW</div>}
|
|
|
|
<FilePrice badge uri={normalizeURI(uri)} />
|
|
|
|
</div>
|
|
|
|
|
2019-03-14 19:40:26 +01:00
|
|
|
<div className="media__actions media__actions--between">
|
|
|
|
<div className="media__subtext media__subtext--large">
|
|
|
|
<div className="media__subtitle__channel">
|
|
|
|
<UriIndicator uri={uri} link />
|
|
|
|
</div>
|
|
|
|
{__('Published on')} <DateTime block={height} show={DateTime.SHOW_DATE} />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="media__subtext--large">
|
|
|
|
{viewCount} {viewCount !== 1 ? __('Views') : __('View')}
|
2018-07-25 02:50:04 +02:00
|
|
|
</div>
|
2018-12-19 06:44:53 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="media__actions media__actions--between">
|
|
|
|
<div className="media__action-group--large">
|
|
|
|
{claimIsMine ? (
|
|
|
|
<Button
|
|
|
|
button="primary"
|
|
|
|
icon={icons.EDIT}
|
|
|
|
label={__('Edit')}
|
|
|
|
onClick={() => {
|
|
|
|
prepareEdit(claim, editUri);
|
|
|
|
navigate('/publish');
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<SubscribeButton uri={channelUri} channelName={channelName} />
|
|
|
|
)}
|
|
|
|
{!claimIsMine && (
|
2018-10-10 07:22:06 +02:00
|
|
|
<Button
|
|
|
|
button="alt"
|
2019-01-22 21:36:28 +01:00
|
|
|
icon={icons.TIP}
|
2018-12-19 06:44:53 +01:00
|
|
|
label={__('Send a tip')}
|
2019-01-08 00:29:40 +01:00
|
|
|
onClick={() => openModal(MODALS.SEND_TIP, { uri })}
|
2018-10-10 07:22:06 +02:00
|
|
|
/>
|
2018-12-19 06:44:53 +01:00
|
|
|
)}
|
|
|
|
<Button
|
|
|
|
button="alt"
|
2019-01-22 21:36:28 +01:00
|
|
|
icon={icons.SHARE}
|
2018-12-19 06:44:53 +01:00
|
|
|
label={__('Share')}
|
2019-01-08 00:29:40 +01:00
|
|
|
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, speechShareable })}
|
2018-12-19 06:44:53 +01:00
|
|
|
/>
|
2018-03-26 23:32:43 +02:00
|
|
|
</div>
|
2018-12-19 06:44:53 +01:00
|
|
|
|
|
|
|
<div className="media__action-group--large">
|
|
|
|
<FileDownloadLink uri={uri} />
|
|
|
|
<FileActions uri={uri} claimId={claim.claim_id} />
|
2018-01-09 02:15:44 +01:00
|
|
|
</div>
|
2018-07-25 02:50:04 +02:00
|
|
|
</div>
|
2018-12-19 06:44:53 +01:00
|
|
|
|
|
|
|
<div className="media__info--large">
|
|
|
|
<FileDetails uri={uri} />
|
|
|
|
</div>
|
|
|
|
</div>
|
2019-01-09 19:39:05 +01:00
|
|
|
<div className="grid-area--related">
|
|
|
|
<RecommendedContent uri={uri} />
|
|
|
|
</div>
|
2018-03-26 23:32:43 +02:00
|
|
|
</Page>
|
2017-06-06 23:19:12 +02:00
|
|
|
);
|
2017-05-12 19:14:06 +02:00
|
|
|
}
|
2017-05-05 07:10:37 +02:00
|
|
|
}
|
2017-05-01 21:59:40 +02:00
|
|
|
|
2017-05-26 02:16:25 +02:00
|
|
|
export default FilePage;
|