Thumbnail fixes #6969

Merged
saltrafael merged 3 commits from thumbnail_fixes into master 2021-08-26 16:51:53 +02:00
7 changed files with 83 additions and 38 deletions

View file

@ -108,7 +108,7 @@ function ChannelForm(props: Props) {
if (isClaimingInitialRewards) { if (isClaimingInitialRewards) {
return __('Claiming credits...'); return __('Claiming credits...');
} }
return creatingChannel || updatingChannel ? __('Submitting') : __('Submit'); return creatingChannel || updatingChannel ? __('Submitting...') : __('Submit');
}, [isClaimingInitialRewards, creatingChannel, updatingChannel]); }, [isClaimingInitialRewards, creatingChannel, updatingChannel]);
const submitDisabled = React.useMemo(() => { const submitDisabled = React.useMemo(() => {
return ( return (
@ -121,7 +121,17 @@ function ChannelForm(props: Props) {
bidError || bidError ||
(isNewChannel && !params.name) (isNewChannel && !params.name)
); );
}, [isClaimingInitialRewards, creatingChannel, updatingChannel, nameError, thumbError, coverError, bidError, isNewChannel, params.name]); }, [
isClaimingInitialRewards,
creatingChannel,
updatingChannel,
nameError,
thumbError,
coverError,
bidError,
isNewChannel,
params.name,
]);
function getChannelParams() { function getChannelParams() {
// fill this in with sdk data // fill this in with sdk data
@ -297,13 +307,8 @@ function ChannelForm(props: Props) {
(coverError && isUpload.cover ? ( (coverError && isUpload.cover ? (
<div className="channel-cover__custom--waiting">{__('This will be visible in a few minutes.')}</div> <div className="channel-cover__custom--waiting">{__('This will be visible in a few minutes.')}</div>
) : ( ) : (
<img <img className="channel-cover__custom" src={coverSrc} onError={() => setCoverError(true)} />
className="channel-cover__custom" ))}
src={coverSrc}
onError={() => setCoverError(true)}
/>
)
)}
<div className="channel__primary-info"> <div className="channel__primary-info">
<div className="channel__edit-thumb"> <div className="channel__edit-thumb">
<Button <Button
@ -328,8 +333,8 @@ function ChannelForm(props: Props) {
thumbnailPreview={thumbnailPreview} thumbnailPreview={thumbnailPreview}
allowGifs allowGifs
showDelayedMessage={isUpload.thumbnail} showDelayedMessage={isUpload.thumbnail}
setThumbError={(v) => setThumbError(v)} setThumbUploadError={setThumbError}
thumbError={thumbError} thumbUploadError={thumbError}
/> />
<h1 className="channel__title"> <h1 className="channel__title">
{params.title || (channelName && '@' + channelName) || (params.name && '@' + params.name)} {params.title || (channelName && '@' + channelName) || (params.name && '@' + params.name)}

View file

@ -25,8 +25,8 @@ type Props = {
hideStakedIndicator?: boolean, hideStakedIndicator?: boolean,
xsmall?: boolean, xsmall?: boolean,
noOptimization?: boolean, noOptimization?: boolean,
setThumbError: (boolean) => void, setThumbUploadError: (boolean) => void,
thumbError: boolean, ThumbUploadError: boolean,
}; };
function ChannelThumbnail(props: Props) { function ChannelThumbnail(props: Props) {
@ -45,13 +45,15 @@ function ChannelThumbnail(props: Props) {
showDelayedMessage = false, showDelayedMessage = false,
noLazyLoad, noLazyLoad,
hideStakedIndicator = false, hideStakedIndicator = false,
setThumbError, setThumbUploadError,
ThumbUploadError,
} = props; } = props;
const [thumbLoadError, setThumbLoadError] = React.useState(ThumbUploadError);
const shouldResolve = claim === undefined; const shouldResolve = claim === undefined;
const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://'); const thumbnail = rawThumbnail && rawThumbnail.trim().replace(/^http:\/\//i, 'https://');
const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://'); const thumbnailPreview = rawThumbnailPreview && rawThumbnailPreview.trim().replace(/^http:\/\//i, 'https://');
const defaultAvater = AVATAR_DEFAULT || Gerbil; const defaultAvatar = AVATAR_DEFAULT || Gerbil;
const channelThumbnail = thumbnailPreview || thumbnail || defaultAvater; const channelThumbnail = thumbnailPreview || thumbnail || defaultAvatar;
const isGif = channelThumbnail && channelThumbnail.endsWith('gif'); const isGif = channelThumbnail && channelThumbnail.endsWith('gif');
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview; const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
@ -91,13 +93,19 @@ function ChannelThumbnail(props: Props) {
> >
{showDelayedMessage ? ( {showDelayedMessage ? (
<div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div> <div className="channel-thumbnail--waiting">{__('This will be visible in a few minutes.')}</div>
) : ( ) : (
<OptimizedImage <OptimizedImage
alt={__('Channel profile picture')} alt={__('Channel profile picture')}
className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'} className={!channelThumbnail ? 'channel-thumbnail__default' : 'channel-thumbnail__custom'}
src={channelThumbnail} src={(!thumbLoadError && channelThumbnail) || defaultAvatar}
loading={noLazyLoad ? undefined : 'lazy'} loading={noLazyLoad ? undefined : 'lazy'}
onError={() => setThumbError(true)} onError={() => {
if (setThumbUploadError) {
setThumbUploadError(true);
} else {
setThumbLoadError(true);
}
}}
/> />
)} )}
{!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />} {!hideStakedIndicator && <ChannelStakedIndicator uri={uri} claim={claim} />}

View file

@ -224,6 +224,7 @@ function PublishForm(props: Props) {
(activeChannelClaim && activeChannelClaim.claim_id); (activeChannelClaim && activeChannelClaim.claim_id);
const nameEdited = isStillEditing && name !== prevName; const nameEdited = isStillEditing && name !== prevName;
const thumbnailUploaded = uploadThumbnailStatus === THUMBNAIL_STATUSES.COMPLETE && thumbnail;
const waitingForFile = waitForFile && !remoteUrl && !filePath; const waitingForFile = waitForFile && !remoteUrl && !filePath;
// If they are editing, they don't need a new file chosen // If they are editing, they don't need a new file chosen
@ -235,7 +236,7 @@ function PublishForm(props: Props) {
thumbnail && thumbnail &&
!bidError && !bidError &&
!emptyPostError && !emptyPostError &&
!thumbnailError && !(thumbnailError && !thumbnailUploaded) &&
!(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS); !(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS);
const isOverwritingExistingClaim = !editingURI && myClaimForUri; const isOverwritingExistingClaim = !editingURI && myClaimForUri;

View file

@ -35,6 +35,7 @@ function PublishFormErrors(props: Props) {
// If there is an error it will be presented as an inline error as well // If there is an error it will be presented as an inline error as well
const isUploadingThumbnail = uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS; const isUploadingThumbnail = uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS;
const thumbnailUploaded = uploadThumbnailStatus === THUMBNAIL_STATUSES.COMPLETE && thumbnail;
return ( return (
<div className="error__text"> <div className="error__text">
@ -48,7 +49,7 @@ function PublishFormErrors(props: Props) {
{!isUploadingThumbnail && !thumbnail && ( {!isUploadingThumbnail && !thumbnail && (
<div>{__('A thumbnail is required. Please upload or provide an image URL above.')}</div> <div>{__('A thumbnail is required. Please upload or provide an image URL above.')}</div>
)} )}
{thumbnailError && <div>{__('Thumbnail is invalid.')}</div>} {thumbnailError && !thumbnailUploaded && <div>{__('Thumbnail is invalid.')}</div>}
{editingURI && !isStillEditing && !filePath && ( {editingURI && !isStillEditing && !filePath && (
<div>{__('Please reselect a file after changing the LBRY URL')}</div> <div>{__('Please reselect a file after changing the LBRY URL')}</div>
)} )}

View file

@ -68,13 +68,13 @@ class SelectThumbnail extends React.PureComponent<Props> {
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video'; isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
} }
let thumbnailSrc; let thumbnailInputSrc;
if (!thumbnail) { if (!thumbnail) {
thumbnailSrc = ThumbnailMissingImage; thumbnailInputSrc = ThumbnailMissingImage;
} else if (thumbnailError) { } else if (thumbnailError) {
thumbnailSrc = ThumbnailBrokenImage; thumbnailInputSrc = ThumbnailBrokenImage;
} else { } else {
thumbnailSrc = thumbnail; thumbnailInputSrc = thumbnail;
} }
/* /*
@ -88,10 +88,10 @@ class SelectThumbnail extends React.PureComponent<Props> {
<div> <div>
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? ( {status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
<div className="column"> <div className="column">
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailSrc})` }}> <div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailInputSrc})` }}>
<img <img
style={{ display: 'none' }} style={{ display: 'none' }}
src={thumbnailSrc} src={thumbnailInputSrc}
alt={__('Thumbnail Preview')} alt={__('Thumbnail Preview')}
onError={() => updatePublishForm({ thumbnailError: true })} onError={() => updatePublishForm({ thumbnailError: true })}
/> />
@ -128,7 +128,16 @@ class SelectThumbnail extends React.PureComponent<Props> {
)} )}
{status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && ( {status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && (
<div className="column column--space-between"> <div className="column column--space-between">
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnail})` }} /> <div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnail})` }}>
{(thumbnailError !== false) && __('This will be visible in a few minutes.')}
<img
style={{ display: 'none' }}
src={thumbnail}
alt={__('Thumbnail Preview')}
onError={() => updatePublishForm({ thumbnailError: true })}
onLoad={() => updatePublishForm({ thumbnailError: false })}
/>
</div>
<div className="column__item"> <div className="column__item">
<p>{__('Upload complete.')}</p> <p>{__('Upload complete.')}</p>
<div className="section__actions"> <div className="section__actions">

View file

@ -4,17 +4,30 @@ import {
selectMyChannelUrls, selectMyChannelUrls,
doFetchChannelListMine, doFetchChannelListMine,
selectFetchingMyChannels, selectFetchingMyChannels,
makeSelectClaimIsPending,
} from 'lbry-redux'; } from 'lbry-redux';
import { doSetActiveChannel } from 'redux/actions/app'; import { doSetActiveChannel } from 'redux/actions/app';
import { selectYoutubeChannels } from 'redux/selectors/user'; import { selectYoutubeChannels } from 'redux/selectors/user';
import ChannelsPage from './view'; import ChannelsPage from './view';
const select = (state) => ({ const select = (state) => {
channelUrls: selectMyChannelUrls(state), const channelUrls = selectMyChannelUrls(state);
channels: selectMyChannelClaims(state), let pendingChannels = [];
fetchingChannels: selectFetchingMyChannels(state), if (channelUrls) {
youtubeChannels: selectYoutubeChannels(state), channelUrls.map((channelUrl) => {
}); const isPendingUrl = makeSelectClaimIsPending(channelUrl)(state);
if (isPendingUrl) pendingChannels.push(channelUrl);
});
}
return {
channelUrls,
channels: selectMyChannelClaims(state),
fetchingChannels: selectFetchingMyChannels(state),
youtubeChannels: selectYoutubeChannels(state),
pendingChannels,
};
};
const perform = (dispatch) => ({ const perform = (dispatch) => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),

View file

@ -20,18 +20,26 @@ type Props = {
fetchingChannels: boolean, fetchingChannels: boolean,
youtubeChannels: ?Array<any>, youtubeChannels: ?Array<any>,
doSetActiveChannel: (string) => void, doSetActiveChannel: (string) => void,
pendingChannels: Array<string>,
}; };
export default function ChannelsPage(props: Props) { export default function ChannelsPage(props: Props) {
const { channels, channelUrls, fetchChannelListMine, fetchingChannels, youtubeChannels, doSetActiveChannel } = props; const {
channelUrls,
fetchChannelListMine,
fetchingChannels,
youtubeChannels,
doSetActiveChannel,
pendingChannels,
} = props;
const [rewardData, setRewardData] = React.useState(); const [rewardData, setRewardData] = React.useState();
const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length); const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length);
const hasPendingChannels = channels && channels.some((channel) => channel.confirmations < 0);
const { push } = useHistory(); const { push } = useHistory();
useEffect(() => { useEffect(() => {
fetchChannelListMine(); fetchChannelListMine();
}, [fetchChannelListMine, hasPendingChannels]); }, [fetchChannelListMine]);
useEffect(() => { useEffect(() => {
Lbryio.call('user_rewards', 'view_rate').then((data) => setRewardData(data)); Lbryio.call('user_rewards', 'view_rate').then((data) => setRewardData(data));
@ -86,7 +94,7 @@ export default function ChannelsPage(props: Props) {
return data.channel_claim_id === claim.claim_id; return data.channel_claim_id === claim.claim_id;
}); });
if (channelRewardData) { if (channelRewardData && !pendingChannels.includes(claim.permanent_url)) {
return ( return (
<span className="claim-preview__custom-properties"> <span className="claim-preview__custom-properties">
<span className="help--inline"> <span className="help--inline">