lbry-desktop/ui/component/claimPreviewTile/view.jsx
infinite-persistence 6e34282cdc Livestream tile/list: show viewer count if data is available
As of this commit, only the Channel Page is fetching the data through the new API, which has the viewer count correctly populated.

For both "0" and "undefined", continue to show as "LIVE".
2022-04-15 08:24:30 -04:00

298 lines
10 KiB
JavaScript

// @flow
import React from 'react';
import classnames from 'classnames';
import { NavLink, withRouter } from 'react-router-dom';
import ClaimPreviewProgress from 'component/claimPreviewProgress';
import FileThumbnail from 'component/fileThumbnail';
import UriIndicator from 'component/uriIndicator';
import Icon from 'component/common/icon';
import TruncatedText from 'component/common/truncated-text';
import DateTime from 'component/dateTime';
import LivestreamDateTime from 'component/livestreamDateTime';
import ChannelThumbnail from 'component/channelThumbnail';
import FileViewCountInline from 'component/fileViewCountInline';
// import SubscribeButton from 'component/subscribeButton';
import useGetThumbnail from 'effects/use-get-thumbnail';
import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url';
import { formatClaimPreviewTitle } from 'util/formatAriaLabel';
import { parseURI } from 'util/lbryURI';
import PreviewOverlayProperties from 'component/previewOverlayProperties';
import FileDownloadLink from 'component/fileDownloadLink';
import FileHideRecommendation from 'component/fileHideRecommendation';
import FileWatchLaterLink from 'component/fileWatchLaterLink';
import ClaimRepostAuthor from 'component/claimRepostAuthor';
import ClaimMenuList from 'component/claimMenuList';
import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
import * as ICONS from 'constants/icons';
import { FYP_ID } from 'constants/urlParams';
// $FlowFixMe cannot resolve ...
import PlaceholderTx from 'static/img/placeholderTx.gif';
type Props = {
uri: string,
date?: any,
claim: ?Claim,
mediaDuration?: string,
resolveUri: (string) => void,
isResolvingUri: boolean,
history: { push: (string) => void },
thumbnail: string,
title: string,
placeholder: boolean,
banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean },
getFile: (string) => void,
streamingUrl: string,
isMature: boolean,
showMature: boolean,
showHiddenByUser?: boolean,
properties?: (Claim) => void,
collectionId?: string,
fypId?: string,
showNoSourceClaims?: boolean,
isLivestream: boolean,
viewCount: string,
isLivestreamActive: boolean,
livestreamViewerCount: ?number,
swipeLayout: boolean,
};
// preview image cards used in related video functionality, channel overview page and homepage
function ClaimPreviewTile(props: Props) {
const {
history,
uri,
date,
isResolvingUri,
thumbnail,
title,
resolveUri,
claim,
placeholder,
banState,
getFile,
streamingUrl,
isMature,
showMature,
showHiddenByUser,
properties,
showNoSourceClaims,
isLivestream,
isLivestreamActive,
livestreamViewerCount,
collectionId,
fypId,
mediaDuration,
viewCount,
swipeLayout = false,
} = props;
const isRepost = claim && claim.repost_channel_url;
const isCollection = claim && claim.value_type === 'collection';
const isStream = claim && claim.value_type === 'stream';
// $FlowFixMe
const isPlayable =
claim &&
// $FlowFixMe
claim.value &&
// $FlowFixMe
claim.value.stream_type &&
// $FlowFixMe
(claim.value.stream_type === 'audio' || claim.value.stream_type === 'video');
const collectionClaimId = isCollection && claim && claim.claim_id;
const shouldFetch = claim === undefined;
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail;
const canonicalUrl = claim && claim.canonical_url;
const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url);
const listId = collectionId || collectionClaimId;
const navigateUrl =
formatLbryUrlForWeb(canonicalUrl || uri || '/') +
(listId ? generateListSearchUrlParams(listId) : '') +
(fypId ? `?${FYP_ID}=${fypId}` : ''); // sigh...
const navLinkProps = {
to: navigateUrl,
onClick: (e) => e.stopPropagation(),
};
let isValid = false;
if (uri) {
try {
parseURI(uri);
isValid = true;
} catch (e) {
isValid = false;
}
}
const signingChannel = claim && claim.signing_channel;
const isChannel = claim && claim.value_type === 'channel';
const channelUri = !isChannel ? signingChannel && signingChannel.permanent_url : claim && claim.permanent_url;
const channelTitle = signingChannel && ((signingChannel.value && signingChannel.value.title) || signingChannel.name);
// Aria-label value for claim preview
let ariaLabelData = isChannel ? title : formatClaimPreviewTitle(title, channelTitle, date, mediaDuration);
function handleClick(e) {
if (navigateUrl) {
history.push(navigateUrl);
}
}
React.useEffect(() => {
if (isValid && !isResolvingUri && shouldFetch && uri) {
resolveUri(uri);
}
}, [isValid, isResolvingUri, uri, resolveUri, shouldFetch]);
let shouldHide = false;
if (isMature && !showMature) {
// Unfortunately needed until this is resolved
// https://github.com/lbryio/lbry-sdk/issues/2785
shouldHide = true;
} else {
shouldHide =
banState.blacklisted || banState.filtered || (!showHiddenByUser && (banState.muted || banState.blocked));
}
if (shouldHide || (isLivestream && !showNoSourceClaims)) {
return null;
}
const isChannelPage = window.location.pathname.startsWith('/@');
const shouldShowViewCount = !(!viewCount || (claim && claim.repost_url) || isLivestream || !isChannelPage);
if (placeholder || (!claim && isResolvingUri)) {
return (
<li
className={classnames('placeholder claim-preview--tile', {
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
})}
>
<div className="media__thumb">
<img src={PlaceholderTx} alt="Placeholder" />
</div>
<div className="placeholder__wrapper">
<div className="claim-tile__title" />
<div className="claim-tile__title_b" />
<div
className={classnames('claim-tile__info', {
contains_view_count: shouldShowViewCount,
})}
>
<div className="channel-thumbnail" />
<div className="claim-tile__about">
<div className="button__content" />
<div className="claim-tile__about--counts" />
</div>
</div>
</div>
</li>
);
}
let liveProperty = null;
if (isLivestream) {
if (isLivestreamActive === true && livestreamViewerCount) {
liveProperty = (claim) => (
<span className="livestream__viewer-count">
{livestreamViewerCount} <Icon icon={ICONS.EYE} />
</span>
);
} else {
liveProperty = (claim) => <>LIVE</>;
}
}
return (
<li
onClick={handleClick}
className={classnames('card claim-preview--tile', {
'claim-preview__wrapper--channel': isChannel,
'claim-preview__live': isLivestreamActive,
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
})}
>
<NavLink {...navLinkProps} role="none" tabIndex={-1} aria-hidden>
<FileThumbnail thumbnail={thumbnailUrl} allowGifs>
{!isChannel && (
<React.Fragment>
<div className="claim-preview__hover-actions">
{isPlayable && <FileWatchLaterLink focusable={false} uri={repostedContentUri} />}
</div>
{fypId && (
<div className="claim-preview__hover-actions">
{isStream && <FileHideRecommendation focusable={false} uri={repostedContentUri} />}
</div>
)}
{/* @if TARGET='app' */}
<div className="claim-preview__hover-actions">
{isStream && <FileDownloadLink focusable={false} uri={canonicalUrl} hideOpenButton />}
</div>
{/* @endif */}
<div className="claim-preview__file-property-overlay">
<PreviewOverlayProperties uri={uri} properties={liveProperty || properties} />
</div>
<ClaimPreviewProgress uri={uri} />
</React.Fragment>
)}
{isCollection && (
<React.Fragment>
<div className="claim-preview__collection-wrapper">
<CollectionPreviewOverlay collectionId={listId} uri={uri} />
</div>
</React.Fragment>
)}
</FileThumbnail>
</NavLink>
<div className="claim-tile__header">
<NavLink aria-label={ariaLabelData} {...navLinkProps}>
<h2 className="claim-tile__title">
<TruncatedText text={title || (claim && claim.name)} lines={isChannel ? 1 : 2} />
{isChannel && (
<div className="claim-tile__about">
<UriIndicator uri={uri} />
</div>
)}
</h2>
</NavLink>
<ClaimMenuList uri={uri} collectionId={listId} fypId={fypId} channelUri={channelUri} />
</div>
<div>
<div
className={classnames('claim-tile__info', {
contains_view_count: shouldShowViewCount,
})}
>
{isChannel ? (
// <div className="claim-tile__about--channel">
// <SubscribeButton uri={repostedChannelUri || uri} />
// </div>
<></>
) : (
<React.Fragment>
<UriIndicator focusable={false} uri={uri} link hideAnonymous>
<ChannelThumbnail uri={channelUri} xsmall checkMembership={false} />
</UriIndicator>
<div className="claim-tile__about">
<UriIndicator uri={uri} link />
<div className="claim-tile__about--counts">
<FileViewCountInline uri={uri} isLivestream={isLivestream} />
{isLivestream && <LivestreamDateTime uri={uri} />}
{!isLivestream && <DateTime timeAgo uri={uri} />}
</div>
</div>
</React.Fragment>
)}
</div>
{isRepost && (
<div className="claim-tile__repost-author">
<ClaimRepostAuthor uri={uri} />
</div>
)}
</div>
</li>
);
}
export default withRouter(ClaimPreviewTile);