Fix list thumbnail upload (#7074)

* Bump redux

* Fix thumbnail upload

* Update changelog
This commit is contained in:
saltrafael 2021-09-13 12:40:31 -03:00 committed by GitHub
parent d5e8f2d18c
commit 69def916a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 214 additions and 344 deletions

View file

@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix comment section redirection to create channel _community pr!_ ([#6557](https://github.com/lbryio/lbry-desktop/pull/6557)) - Fix comment section redirection to create channel _community pr!_ ([#6557](https://github.com/lbryio/lbry-desktop/pull/6557))
- Clicking on the title of a floating player will take you back to the list ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921)) - Clicking on the title of a floating player will take you back to the list ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
- Fix floating player stopping on markdown or image files ([#7073](https://github.com/lbryio/lbry-desktop/pull/7073)) - Fix floating player stopping on markdown or image files ([#7073](https://github.com/lbryio/lbry-desktop/pull/7073))
- Fix list thumbnail upload ([#7074](https://github.com/lbryio/lbry-desktop/pull/7074))
## [0.51.1] - [2021-06-26] ## [0.51.1] - [2021-06-26]

View file

@ -155,7 +155,7 @@
"imagesloaded": "^4.1.4", "imagesloaded": "^4.1.4",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#372e559caee6af2b2d927e5d42419a71c3d15b57", "lbry-redux": "lbryio/lbry-redux#129b0ea3faa5da69ef1b85ea9ab7777b06aa3264",
"lbryinc": "lbryio/lbryinc#0b4e41ef90d6347819dd3453f2f9398a5c1b4f36", "lbryinc": "lbryio/lbryinc#0b4e41ef90d6347819dd3453f2f9398a5c1b4f36",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",

View file

@ -17,7 +17,6 @@ import {
makeSelectClaimIdsForCollectionId, makeSelectClaimIdsForCollectionId,
ACTIONS as LBRY_REDUX_ACTIONS, ACTIONS as LBRY_REDUX_ACTIONS,
} from 'lbry-redux'; } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import CollectionForm from './view'; import CollectionForm from './view';
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app'; import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
@ -44,7 +43,6 @@ const select = (state, props) => ({
}); });
const perform = (dispatch) => ({ const perform = (dispatch) => ({
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
publishCollectionUpdate: (params) => dispatch(doCollectionPublishUpdate(params)), publishCollectionUpdate: (params) => dispatch(doCollectionPublishUpdate(params)),
publishCollection: (params, collectionId) => dispatch(doCollectionPublish(params, collectionId)), publishCollection: (params, collectionId) => dispatch(doCollectionPublish(params, collectionId)),
clearCollectionErrors: () => dispatch({ type: LBRY_REDUX_ACTIONS.CLEAR_COLLECTION_ERRORS }), clearCollectionErrors: () => dispatch({ type: LBRY_REDUX_ACTIONS.CLEAR_COLLECTION_ERRORS }),

View file

@ -10,9 +10,9 @@ import ChannelSelector from 'component/channelSelector';
import ClaimList from 'component/claimList'; import ClaimList from 'component/claimList';
import Card from 'component/common/card'; import Card from 'component/common/card';
import LbcSymbol from 'component/common/lbc-symbol'; import LbcSymbol from 'component/common/lbc-symbol';
import ThumbnailPicker from 'component/thumbnailPicker'; import SelectThumbnail from 'component/selectThumbnail';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { isNameValid, regexInvalidURI } from 'lbry-redux'; import { isNameValid, regexInvalidURI, THUMBNAIL_STATUSES } from 'lbry-redux';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs'; import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
import { handleBidChange } from 'util/publish'; import { handleBidChange } from 'util/publish';
@ -21,6 +21,7 @@ import { INVALID_NAME_ERROR } from 'constants/claim';
import SUPPORTED_LANGUAGES from 'constants/supported_languages'; import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import analytics from 'analytics'; import analytics from 'analytics';
const LANG_NONE = 'none'; const LANG_NONE = 'none';
const MAX_TAG_SELECT = 5; const MAX_TAG_SELECT = 5;
@ -39,23 +40,18 @@ type Props = {
tags: Array<string>, tags: Array<string>,
locations: Array<string>, locations: Array<string>,
languages: Array<string>, languages: Array<string>,
collectionId: string, collectionId: string,
collection: Collection, collection: Collection,
collectionClaimIds: Array<string>, collectionClaimIds: Array<string>,
collectionUrls: Array<string>, collectionUrls: Array<string>,
publishCollectionUpdate: (CollectionUpdateParams) => Promise<any>,
updatingCollection: boolean, updatingCollection: boolean,
updateError: string, updateError: string,
publishCollection: (CollectionPublishParams, string) => Promise<any>,
createError: string, createError: string,
creatingCollection: boolean, creatingCollection: boolean,
publishCollectionUpdate: (CollectionUpdateParams) => Promise<any>,
publishCollection: (CollectionPublishParams, string) => Promise<any>,
clearCollectionErrors: () => void, clearCollectionErrors: () => void,
onDone: (string) => void, onDone: (string) => void,
openModal: (
id: string,
{ onUpdate: (string) => void, assetName: string, helpText: string, currentValue: string, title: string }
) => void,
}; };
function CollectionForm(props: Props) { function CollectionForm(props: Props) {
@ -72,11 +68,8 @@ function CollectionForm(props: Props) {
locations, locations,
languages = [], languages = [],
// rest // rest
onDone,
publishCollectionUpdate,
updateError, updateError,
updatingCollection, updatingCollection,
publishCollection,
creatingCollection, creatingCollection,
createError, createError,
disabled, disabled,
@ -86,7 +79,10 @@ function CollectionForm(props: Props) {
collection, collection,
collectionUrls, collectionUrls,
collectionClaimIds, collectionClaimIds,
publishCollectionUpdate,
publishCollection,
clearCollectionErrors, clearCollectionErrors,
onDone,
} = props; } = props;
const activeChannelName = activeChannelClaim && activeChannelClaim.name; const activeChannelName = activeChannelClaim && activeChannelClaim.name;
let prefix = IS_WEB ? `${DOMAIN}/` : 'lbry://'; let prefix = IS_WEB ? `${DOMAIN}/` : 'lbry://';
@ -107,6 +103,11 @@ function CollectionForm(props: Props) {
const secondaryLanguage = Array.isArray(languageParam) && languageParam.length >= 2 && languageParam[1]; const secondaryLanguage = Array.isArray(languageParam) && languageParam.length >= 2 && languageParam[1];
const collectionClaimIdsString = JSON.stringify(collectionClaimIds); const collectionClaimIdsString = JSON.stringify(collectionClaimIds);
const itemError = !params.claims.length ? __('Cannot publish empty list') : '';
const thumbnailError =
(params.thumbnail_error && params.thumbnail_status !== THUMBNAIL_STATUSES.COMPLETE && __('Invalid thumbnail')) ||
(params.thumbnail_status === THUMBNAIL_STATUSES.IN_PROGRESS && __('Please wait for thumbnail to finish uploading'));
const submitError = nameError || bidError || itemError || updateError || createError || thumbnailError;
function parseName(newName) { function parseName(newName) {
let INVALID_URI_CHARS = new RegExp(regexInvalidURI, 'gu'); let INVALID_URI_CHARS = new RegExp(regexInvalidURI, 'gu');
@ -142,6 +143,8 @@ function CollectionForm(props: Props) {
function getCollectionParams() { function getCollectionParams() {
const collectionParams: { const collectionParams: {
thumbnail_url?: string, thumbnail_url?: string,
thumbnail_error?: boolean,
thumbnail_status?: string,
name?: string, name?: string,
description?: string, description?: string,
title?: string, title?: string,
@ -154,7 +157,9 @@ function CollectionForm(props: Props) {
claims: ?Array<string>, claims: ?Array<string>,
} = { } = {
thumbnail_url: thumbnailUrl, thumbnail_url: thumbnailUrl,
name: parseName(collectionName),
description, description,
title: claim ? title : collectionName,
bid: String(amount || 0.001), bid: String(amount || 0.001),
languages: languages ? dedupeLanguages(languages) : [], languages: languages ? dedupeLanguages(languages) : [],
locations: locations || [], locations: locations || [],
@ -163,32 +168,14 @@ function CollectionForm(props: Props) {
return { name: tag }; return { name: tag };
}) })
: [], : [],
claim_id: String(claim && claim.claim_id),
channel_id: String(activeChannelId && parseName(collectionName)),
claims: collectionClaimIds, claims: collectionClaimIds,
}; };
collectionParams['name'] = parseName(collectionName);
if (activeChannelId) {
collectionParams['channel_id'] = activeChannelId;
}
if (!claim) {
collectionParams['title'] = collectionName;
}
if (claim) {
collectionParams['claim_id'] = claim.claim_id;
collectionParams['title'] = title;
}
return collectionParams; return collectionParams;
} }
React.useEffect(() => {
const collectionClaimIds = JSON.parse(collectionClaimIdsString);
setParams({ ...params, claims: collectionClaimIds });
clearCollectionErrors();
}, [collectionClaimIdsString, setParams]);
function handleLanguageChange(index, code) { function handleLanguageChange(index, code) {
let langs = [...languageParam]; let langs = [...languageParam];
if (index === 0) { if (index === 0) {
@ -211,10 +198,6 @@ function CollectionForm(props: Props) {
setParams({ ...params, languages: langs }); setParams({ ...params, languages: langs });
} }
function handleThumbnailChange(thumbnailUrl: string) {
setParams({ ...params, thumbnail_url: thumbnailUrl });
}
function handleSubmit() { function handleSubmit() {
if (uri) { if (uri) {
publishCollectionUpdate(params).then((pendingClaim) => { publishCollectionUpdate(params).then((pendingClaim) => {
@ -235,6 +218,12 @@ function CollectionForm(props: Props) {
} }
} }
React.useEffect(() => {
const collectionClaimIds = JSON.parse(collectionClaimIdsString);
setParams({ ...params, claims: collectionClaimIds });
clearCollectionErrors();
}, [collectionClaimIdsString, setParams]);
React.useEffect(() => { React.useEffect(() => {
let nameError; let nameError;
if (!name && name !== undefined) { if (!name && name !== undefined) {
@ -247,17 +236,14 @@ function CollectionForm(props: Props) {
}, [name]); }, [name]);
React.useEffect(() => { React.useEffect(() => {
if (incognito) { if (incognito && params.channel_id) {
const newParams = Object.assign({}, params); const newParams = Object.assign({}, params);
delete newParams.channel_id; delete newParams.channel_id;
setParams(newParams); setParams(newParams);
} else if (activeChannelId) { } else if (activeChannelId && params.channel_id !== activeChannelId) {
setParams({ ...params, channel_id: activeChannelId }); setParams({ ...params, channel_id: activeChannelId });
} }
}, [activeChannelId, incognito, setParams]); }, [activeChannelId, incognito, params, setParams]);
const itemError = !params.claims.length ? __('Cannot publish empty list') : '';
const submitError = nameError || bidError || itemError || updateError || createError;
return ( return (
<> <>
@ -277,11 +263,6 @@ function CollectionForm(props: Props) {
<Card <Card
body={ body={
<> <>
<fieldset-group className="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section>
<label htmlFor="channel_name">{__('Channel')}</label>
</fieldset-section>
</fieldset-group>
<fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix"> <fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section> <fieldset-section>
<label htmlFor="channel_name">{__('Name')}</label> <label htmlFor="channel_name">{__('Name')}</label>
@ -311,11 +292,15 @@ function CollectionForm(props: Props) {
value={params.title} value={params.title}
onChange={(e) => setParams({ ...params, title: e.target.value })} onChange={(e) => setParams({ ...params, title: e.target.value })}
/> />
<ThumbnailPicker <fieldset-section>
inline <SelectThumbnail
thumbnailParam={params.thumbnail_url} thumbnailParam={params.thumbnail_url}
updateThumbnailParam={handleThumbnailChange} thumbnailParamError={params.thumbnail_error}
thumbnailParamStatus={params.thumbnail_status}
updateThumbnailParams={setParam}
publishForm={false}
/> />
</fieldset-section>
<FormField <FormField
type="markdown" type="markdown"
name="content_description2" name="content_description2"
@ -436,7 +421,14 @@ function CollectionForm(props: Props) {
<div className="section__actions"> <div className="section__actions">
<Button <Button
button="primary" button="primary"
disabled={creatingCollection || updatingCollection || nameError || bidError || !params.claims.length} disabled={
creatingCollection ||
updatingCollection ||
nameError ||
bidError ||
thumbnailError ||
!params.claims.length
}
label={creatingCollection || updatingCollection ? __('Submitting') : __('Submit')} label={creatingCollection || updatingCollection ? __('Submitting') : __('Submit')}
onClick={handleSubmit} onClick={handleSubmit}
/> />

View file

@ -46,10 +46,11 @@ function PublishFormErrors(props: Props) {
{!bid && <div>{__('A deposit amount is required')}</div>} {!bid && <div>{__('A deposit amount is required')}</div>}
{bidError && <div>{__('Please check your deposit amount.')}</div>} {bidError && <div>{__('Please check your deposit amount.')}</div>}
{isUploadingThumbnail && <div>{__('Please wait for thumbnail to finish uploading')}</div>} {isUploadingThumbnail && <div>{__('Please wait for thumbnail to finish uploading')}</div>}
{!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 && !thumbnailUploaded && <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

@ -6,23 +6,19 @@ import {
selectFileInfosByOutpoint, selectFileInfosByOutpoint,
doResetThumbnailStatus, doResetThumbnailStatus,
} from 'lbry-redux'; } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import PublishPage from './view'; import PublishPage from './view';
const select = state => ({ const select = (state) => ({
...selectPublishFormValues(state), ...selectPublishFormValues(state),
fileInfos: selectFileInfosByOutpoint(state), fileInfos: selectFileInfosByOutpoint(state),
myClaimForUri: selectMyClaimForUri(state), myClaimForUri: selectMyClaimForUri(state),
}); });
const perform = dispatch => ({ const perform = (dispatch) => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: (value) => dispatch(doUpdatePublishForm(value)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()), resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
}); });
export default connect( export default connect(select, perform)(PublishPage);
select,
perform
)(PublishPage);

View file

@ -16,45 +16,42 @@ type Props = {
thumbnail: ?string, thumbnail: ?string,
formDisabled: boolean, formDisabled: boolean,
uploadThumbnailStatus: string, uploadThumbnailStatus: string,
publishForm: boolean,
thumbnailPath: ?string, thumbnailPath: ?string,
thumbnailError: ?string, thumbnailError: ?string,
thumbnailParam: ?string,
thumbnailParamError: boolean,
thumbnailParamStatus: string,
openModal: (id: string, {}) => void, openModal: (id: string, {}) => void,
updatePublishForm: ({}) => void, updatePublishForm: ({}) => void,
updateThumbnailParams: ({}) => void,
resetThumbnailStatus: () => void, resetThumbnailStatus: () => void,
}; };
class SelectThumbnail extends React.PureComponent<Props> { function SelectThumbnail(props: Props) {
constructor() {
super();
(this: any).handleThumbnailChange = this.handleThumbnailChange.bind(this);
}
handleThumbnailChange(e: SyntheticInputEvent<*>) {
const { updatePublishForm } = this.props;
const newThumbnail = e.target.value.replace(' ', '');
updatePublishForm({
thumbnail: newThumbnail,
thumbnailError: newThumbnail.startsWith('data:image'),
});
}
render() {
const { const {
filePath, filePath,
fileInfos, fileInfos,
myClaimForUri, myClaimForUri,
thumbnail,
formDisabled, formDisabled,
publishForm = true,
uploadThumbnailStatus: status, uploadThumbnailStatus: status,
openModal, openModal,
updatePublishForm, updatePublishForm,
thumbnailParam,
thumbnailParamStatus,
updateThumbnailParams,
thumbnailPath, thumbnailPath,
thumbnailError,
resetThumbnailStatus, resetThumbnailStatus,
} = this.props; } = props;
const thumbnail = publishForm ? props.thumbnail : thumbnailParam;
const thumbnailError = publishForm ? props.thumbnailError : props.thumbnailParamError;
const accept = '.png, .jpg, .jpeg, .gif'; const accept = '.png, .jpg, .jpeg, .gif';
const manualInput = status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL;
const thumbUploaded = status === THUMBNAIL_STATUSES.COMPLETE && thumbnail;
const isUrlInput = thumbnail !== ThumbnailMissingImage && thumbnail !== ThumbnailBrokenImage;
const outpoint = myClaimForUri ? `${myClaimForUri.txid}:${myClaimForUri.nout}` : undefined; const outpoint = myClaimForUri ? `${myClaimForUri.txid}:${myClaimForUri.nout}` : undefined;
const fileInfo = outpoint ? fileInfos[outpoint] : undefined; const fileInfo = outpoint ? fileInfos[outpoint] : undefined;
@ -68,13 +65,30 @@ class SelectThumbnail extends React.PureComponent<Props> {
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video'; isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
} }
let thumbnailInputSrc; function handleThumbnailChange(e: SyntheticInputEvent<*>) {
if (!thumbnail) { const newThumbnail = e.target.value.replace(' ', '');
thumbnailInputSrc = ThumbnailMissingImage;
} else if (thumbnailError) { if (updateThumbnailParams) {
thumbnailInputSrc = ThumbnailBrokenImage; updateThumbnailParams({ thumbnail_url: newThumbnail });
} else { } else {
thumbnailInputSrc = thumbnail; updatePublishForm({ thumbnail: newThumbnail });
}
}
React.useEffect(() => {
if (updateThumbnailParams && status !== thumbnailParamStatus) {
updateThumbnailParams({ thumbnail_status: status });
}
}, [status, thumbnailParamStatus, updateThumbnailParams]);
let thumbnailSrc;
if (!thumbnail) {
thumbnailSrc = ThumbnailMissingImage;
} else if (thumbnailError) {
thumbnailSrc =
(manualInput && ThumbnailBrokenImage) || (status !== THUMBNAIL_STATUSES.COMPLETE && ThumbnailMissingImage);
} else {
thumbnailSrc = thumbnail;
} }
/* /*
@ -83,20 +97,42 @@ class SelectThumbnail extends React.PureComponent<Props> {
the proper aspect ratio. This is to avoid blackbars on the side of images and inconsistent thumbnails the proper aspect ratio. This is to avoid blackbars on the side of images and inconsistent thumbnails
We still need to render the image to see if there is an error loading the url We still need to render the image to see if there is an error loading the url
*/ */
const thumbPreview = (
return ( <div className="column__item thumbnail-picker__preview" style={{ backgroundImage: `url(${String(thumbnailSrc)})` }}>
<div> {thumbUploaded && thumbnailError !== false && __('This will be visible in a few minutes.')}
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
<div className="column">
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailInputSrc})` }}>
<img <img
style={{ display: 'none' }} style={{ display: 'none' }}
src={thumbnailInputSrc} src={thumbnail}
alt={__('Thumbnail Preview')} alt={__('Thumbnail Preview')}
onError={() => updatePublishForm({ thumbnailError: true })} onError={() =>
publishForm
? updatePublishForm({ thumbnailError: true })
: updateThumbnailParams({ thumbnail_error: Boolean(thumbnail) })
}
onLoad={() =>
publishForm
? updatePublishForm({ thumbnailError: !isUrlInput })
: updateThumbnailParams({ thumbnail_error: !isUrlInput })
}
/> />
</div> </div>
);
return (
<>
{status !== THUMBNAIL_STATUSES.IN_PROGRESS && (
<div className="column">
{thumbPreview}
{publishForm && thumbUploaded ? (
<div className="column__item"> <div className="column__item">
<p>{__('Upload complete.')}</p>
<div className="section__actions">
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
</div>
</div>
) : (
<div className="column__item">
{manualInput ? (
<FormField <FormField
type="text" type="text"
name="content_thumbnail" name="content_thumbnail"
@ -104,58 +140,33 @@ class SelectThumbnail extends React.PureComponent<Props> {
placeholder="https://images.fbi.gov/alien" placeholder="https://images.fbi.gov/alien"
value={thumbnail} value={thumbnail}
disabled={formDisabled} disabled={formDisabled}
onChange={this.handleThumbnailChange} onChange={handleThumbnailChange}
/> />
<div className="card__actions">
<Button
button="link"
label={__('Use thumbnail upload tool')}
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.READY })}
/>
</div>
</div>
</div>
) : ( ) : (
<React.Fragment>
{status === THUMBNAIL_STATUSES.READY && (
<FileSelector <FileSelector
currentPath={thumbnailPath} currentPath={thumbnailPath}
label={__('Thumbnail')} label={__('Thumbnail')}
placeholder={__('Choose an enticing thumbnail')} placeholder={__('Choose an enticing thumbnail')}
accept={accept} accept={accept}
onFileChosen={(file) => openModal(MODALS.CONFIRM_THUMBNAIL_UPLOAD, { file })} onFileChosen={(file) =>
openModal(MODALS.CONFIRM_THUMBNAIL_UPLOAD, {
file,
cb: (url) => !publishForm && updateThumbnailParams({ thumbnail_url: url }),
})
}
/> />
)} )}
{status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && ( <div className="card__actions">
<div className="column column--space-between">
<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">
<p>{__('Upload complete.')}</p>
<div className="section__actions">
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
</div>
</div>
</div>
)}
</React.Fragment>
)}
{status === THUMBNAIL_STATUSES.READY && (
<div className="section__actions">
<Button <Button
button="link" button="link"
label={__('Enter a thumbnail URL')} label={manualInput ? __('Use thumbnail upload tool') : __('Enter a thumbnail URL')}
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.MANUAL })} onClick={() =>
updatePublishForm({
uploadThumbnailStatus: manualInput ? THUMBNAIL_STATUSES.READY : THUMBNAIL_STATUSES.MANUAL,
})
}
/> />
{isSupportedVideo && IS_WEB && ( {status === THUMBNAIL_STATUSES.READY && isSupportedVideo && IS_WEB && (
// Disabled on desktop until this is resolved // Disabled on desktop until this is resolved
// https://github.com/electron/electron/issues/20750#issuecomment-709505902 // https://github.com/electron/electron/issues/20750#issuecomment-709505902
<Button <Button
@ -165,19 +176,21 @@ class SelectThumbnail extends React.PureComponent<Props> {
/> />
)} )}
</div> </div>
</div>
)}
</div>
)} )}
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>} {status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
{status !== THUMBNAIL_STATUSES.COMPLETE && ( {!thumbUploaded && (
<p className="help"> <p className="help">
{status === THUMBNAIL_STATUSES.API_DOWN {manualInput
? __('Enter a URL for your thumbnail.') ? __('Enter a URL for your thumbnail.')
: __('Upload your thumbnail to %domain%. Recommended size is 16:9.', { domain: DOMAIN })} : __('Upload your thumbnail to %domain%. Recommended size is 16:9.', { domain: DOMAIN })}
</p> </p>
)} )}
</div> </>
); );
}
} }
export default SelectThumbnail; export default SelectThumbnail;

View file

@ -1,13 +0,0 @@
import { connect } from 'react-redux';
import ThumbnailPicker from './view';
import { makeSelectThumbnailForUri } from 'lbry-redux';
const select = (state, props) => ({
thumbnailForUri: makeSelectThumbnailForUri(props.uri)(state),
});
// const perform = dispatch => ({
// });
export default connect(select)(ThumbnailPicker);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -1,116 +0,0 @@
// @flow
import * as React from 'react';
import Card from 'component/common/card';
import ThumbnailMissingImage from './thumbnail-missing.png';
import SelectAsset from 'component/selectAsset';
type Props = {
// uploadThumbnailStatus: string,
thumbnailParam: string,
thumbnailForUri: string,
updateThumbnailParam: (string) => void,
inline?: boolean,
};
const ThumbnailPicker = (props: Props) => {
const { thumbnailForUri, thumbnailParam, updateThumbnailParam, inline } = props;
// uploadThumbnailStatus
// {status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
// {status === THUMBNAIL_STATUSES.READY && (
// {status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && (
const [thumbError, setThumbError] = React.useState(false); // possibly existing URL
const updateThumb = (thumb: string) => {
setThumbError(false);
updateThumbnailParam(thumb);
};
if (inline) {
return (
<fieldset-section>
<label>{__('Thumbnail')}</label>
<div className="column">
{thumbError && (
<div
className="column__item thumbnail-picker__preview"
style={{ backgroundImage: `url(${ThumbnailMissingImage})` }}
/>
)}
{!thumbError && (
<div
className="column__item thumbnail-picker__preview"
style={{ backgroundImage: `url(${thumbnailParam || thumbnailForUri})` }}
>
<img
style={{ display: 'none' }}
src={thumbnailParam || thumbnailForUri}
alt={__('Thumbnail Preview')}
onError={() => {
if (thumbnailParam) {
setThumbError(true);
}
}}
/>
</div>
)}
<div className="column__item">
{/* if upload */}
<SelectAsset
inline
onUpdate={updateThumb}
currentValue={thumbnailParam}
assetName={'Image'}
recommended={__('(16:9)')}
/>
</div>
</div>
</fieldset-section>
);
}
return (
<div>
<Card
body={
<div className="column">
{thumbError && (
<div
className="column__item thumbnail-preview"
style={{ backgroundImage: `url(${ThumbnailMissingImage})` }}
/>
)}
{!thumbError && (
<div
className="column__item thumbnail-preview"
style={{ backgroundImage: `url(${thumbnailParam || thumbnailForUri})` }}
>
<img
style={{ display: 'none' }}
src={thumbnailParam || thumbnailForUri}
alt={__('Thumbnail Preview')}
onError={() => {
if (thumbnailParam) {
setThumbError(true);
}
}}
/>
</div>
)}
<div className="column__item">
{/* if upload */}
<SelectAsset
inline
onUpdate={updateThumb}
currentValue={thumbnailParam}
assetName={'Thumbnail'}
recommended={__('(16:9)')}
/>
</div>
</div>
}
/>
</div>
);
};
export default ThumbnailPicker;

View file

@ -3,13 +3,10 @@ import { doHideModal } from 'redux/actions/app';
import { doUploadThumbnail, doUpdatePublishForm } from 'lbry-redux'; import { doUploadThumbnail, doUpdatePublishForm } from 'lbry-redux';
import ModalConfirmThumbnailUpload from './view'; import ModalConfirmThumbnailUpload from './view';
const perform = dispatch => ({ const perform = (dispatch) => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
upload: file => dispatch(doUploadThumbnail(null, file, null, null, file.path)), upload: (file, cb) => dispatch(doUploadThumbnail(null, file, null, null, file.path, cb)),
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: (value) => dispatch(doUpdatePublishForm(value)),
}); });
export default connect( export default connect(null, perform)(ModalConfirmThumbnailUpload);
null,
perform
)(ModalConfirmThumbnailUpload);

View file

@ -4,17 +4,18 @@ import { Modal } from 'modal/modal';
import { DOMAIN } from 'config'; import { DOMAIN } from 'config';
type Props = { type Props = {
upload: WebFile => void,
file: WebFile, file: WebFile,
upload: (WebFile, (string) => void) => void,
cb: (string) => void,
closeModal: () => void, closeModal: () => void,
updatePublishForm: ({}) => void, updatePublishForm: ({}) => void,
}; };
class ModalConfirmThumbnailUpload extends React.PureComponent<Props> { class ModalConfirmThumbnailUpload extends React.PureComponent<Props> {
upload() { upload() {
const { upload, updatePublishForm, closeModal, file } = this.props; const { upload, updatePublishForm, cb, closeModal, file } = this.props;
if (file) { if (file) {
upload(file); upload(file, cb);
updatePublishForm({ thumbnailPath: file.path }); updatePublishForm({ thumbnailPath: file.path });
closeModal(); closeModal();
} }

View file

@ -10139,9 +10139,9 @@ lazy-val@^1.0.4:
yargs "^13.2.2" yargs "^13.2.2"
zstd-codec "^0.1.1" zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#372e559caee6af2b2d927e5d42419a71c3d15b57: lbry-redux@lbryio/lbry-redux#129b0ea3faa5da69ef1b85ea9ab7777b06aa3264:
version "0.0.1" version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/372e559caee6af2b2d927e5d42419a71c3d15b57" resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/129b0ea3faa5da69ef1b85ea9ab7777b06aa3264"
dependencies: dependencies:
"@ungap/from-entries" "^0.2.1" "@ungap/from-entries" "^0.2.1"
proxy-polyfill "0.1.6" proxy-polyfill "0.1.6"