Fix list thumbnail upload (#7074)
* Bump redux * Fix thumbnail upload * Update changelog
This commit is contained in:
parent
d5e8f2d18c
commit
69def916a8
14 changed files with 214 additions and 344 deletions
|
@ -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))
|
||||
- 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 list thumbnail upload ([#7074](https://github.com/lbryio/lbry-desktop/pull/7074))
|
||||
|
||||
## [0.51.1] - [2021-06-26]
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
"imagesloaded": "^4.1.4",
|
||||
"json-loader": "^0.5.4",
|
||||
"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",
|
||||
"lint-staged": "^7.0.2",
|
||||
"localforage": "^1.7.1",
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
makeSelectClaimIdsForCollectionId,
|
||||
ACTIONS as LBRY_REDUX_ACTIONS,
|
||||
} from 'lbry-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
|
||||
import CollectionForm from './view';
|
||||
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
||||
|
@ -44,7 +43,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
publishCollectionUpdate: (params) => dispatch(doCollectionPublishUpdate(params)),
|
||||
publishCollection: (params, collectionId) => dispatch(doCollectionPublish(params, collectionId)),
|
||||
clearCollectionErrors: () => dispatch({ type: LBRY_REDUX_ACTIONS.CLEAR_COLLECTION_ERRORS }),
|
||||
|
|
|
@ -10,9 +10,9 @@ import ChannelSelector from 'component/channelSelector';
|
|||
import ClaimList from 'component/claimList';
|
||||
import Card from 'component/common/card';
|
||||
import LbcSymbol from 'component/common/lbc-symbol';
|
||||
import ThumbnailPicker from 'component/thumbnailPicker';
|
||||
import SelectThumbnail from 'component/selectThumbnail';
|
||||
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 { FormField } from 'component/common/form';
|
||||
import { handleBidChange } from 'util/publish';
|
||||
|
@ -21,6 +21,7 @@ import { INVALID_NAME_ERROR } from 'constants/claim';
|
|||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import analytics from 'analytics';
|
||||
|
||||
const LANG_NONE = 'none';
|
||||
const MAX_TAG_SELECT = 5;
|
||||
|
||||
|
@ -39,23 +40,18 @@ type Props = {
|
|||
tags: Array<string>,
|
||||
locations: Array<string>,
|
||||
languages: Array<string>,
|
||||
|
||||
collectionId: string,
|
||||
collection: Collection,
|
||||
collectionClaimIds: Array<string>,
|
||||
collectionUrls: Array<string>,
|
||||
publishCollectionUpdate: (CollectionUpdateParams) => Promise<any>,
|
||||
updatingCollection: boolean,
|
||||
updateError: string,
|
||||
publishCollection: (CollectionPublishParams, string) => Promise<any>,
|
||||
createError: string,
|
||||
creatingCollection: boolean,
|
||||
publishCollectionUpdate: (CollectionUpdateParams) => Promise<any>,
|
||||
publishCollection: (CollectionPublishParams, string) => Promise<any>,
|
||||
clearCollectionErrors: () => void,
|
||||
onDone: (string) => void,
|
||||
openModal: (
|
||||
id: string,
|
||||
{ onUpdate: (string) => void, assetName: string, helpText: string, currentValue: string, title: string }
|
||||
) => void,
|
||||
};
|
||||
|
||||
function CollectionForm(props: Props) {
|
||||
|
@ -72,11 +68,8 @@ function CollectionForm(props: Props) {
|
|||
locations,
|
||||
languages = [],
|
||||
// rest
|
||||
onDone,
|
||||
publishCollectionUpdate,
|
||||
updateError,
|
||||
updatingCollection,
|
||||
publishCollection,
|
||||
creatingCollection,
|
||||
createError,
|
||||
disabled,
|
||||
|
@ -86,7 +79,10 @@ function CollectionForm(props: Props) {
|
|||
collection,
|
||||
collectionUrls,
|
||||
collectionClaimIds,
|
||||
publishCollectionUpdate,
|
||||
publishCollection,
|
||||
clearCollectionErrors,
|
||||
onDone,
|
||||
} = props;
|
||||
const activeChannelName = activeChannelClaim && activeChannelClaim.name;
|
||||
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 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) {
|
||||
let INVALID_URI_CHARS = new RegExp(regexInvalidURI, 'gu');
|
||||
|
@ -142,6 +143,8 @@ function CollectionForm(props: Props) {
|
|||
function getCollectionParams() {
|
||||
const collectionParams: {
|
||||
thumbnail_url?: string,
|
||||
thumbnail_error?: boolean,
|
||||
thumbnail_status?: string,
|
||||
name?: string,
|
||||
description?: string,
|
||||
title?: string,
|
||||
|
@ -154,7 +157,9 @@ function CollectionForm(props: Props) {
|
|||
claims: ?Array<string>,
|
||||
} = {
|
||||
thumbnail_url: thumbnailUrl,
|
||||
name: parseName(collectionName),
|
||||
description,
|
||||
title: claim ? title : collectionName,
|
||||
bid: String(amount || 0.001),
|
||||
languages: languages ? dedupeLanguages(languages) : [],
|
||||
locations: locations || [],
|
||||
|
@ -163,32 +168,14 @@ function CollectionForm(props: Props) {
|
|||
return { name: tag };
|
||||
})
|
||||
: [],
|
||||
claim_id: String(claim && claim.claim_id),
|
||||
channel_id: String(activeChannelId && parseName(collectionName)),
|
||||
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;
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
const collectionClaimIds = JSON.parse(collectionClaimIdsString);
|
||||
setParams({ ...params, claims: collectionClaimIds });
|
||||
clearCollectionErrors();
|
||||
}, [collectionClaimIdsString, setParams]);
|
||||
|
||||
function handleLanguageChange(index, code) {
|
||||
let langs = [...languageParam];
|
||||
if (index === 0) {
|
||||
|
@ -211,10 +198,6 @@ function CollectionForm(props: Props) {
|
|||
setParams({ ...params, languages: langs });
|
||||
}
|
||||
|
||||
function handleThumbnailChange(thumbnailUrl: string) {
|
||||
setParams({ ...params, thumbnail_url: thumbnailUrl });
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
if (uri) {
|
||||
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(() => {
|
||||
let nameError;
|
||||
if (!name && name !== undefined) {
|
||||
|
@ -247,17 +236,14 @@ function CollectionForm(props: Props) {
|
|||
}, [name]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (incognito) {
|
||||
if (incognito && params.channel_id) {
|
||||
const newParams = Object.assign({}, params);
|
||||
delete newParams.channel_id;
|
||||
setParams(newParams);
|
||||
} else if (activeChannelId) {
|
||||
} else if (activeChannelId && params.channel_id !== activeChannelId) {
|
||||
setParams({ ...params, channel_id: activeChannelId });
|
||||
}
|
||||
}, [activeChannelId, incognito, setParams]);
|
||||
|
||||
const itemError = !params.claims.length ? __('Cannot publish empty list') : '';
|
||||
const submitError = nameError || bidError || itemError || updateError || createError;
|
||||
}, [activeChannelId, incognito, params, setParams]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -277,11 +263,6 @@ function CollectionForm(props: Props) {
|
|||
<Card
|
||||
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-section>
|
||||
<label htmlFor="channel_name">{__('Name')}</label>
|
||||
|
@ -311,11 +292,15 @@ function CollectionForm(props: Props) {
|
|||
value={params.title}
|
||||
onChange={(e) => setParams({ ...params, title: e.target.value })}
|
||||
/>
|
||||
<ThumbnailPicker
|
||||
inline
|
||||
thumbnailParam={params.thumbnail_url}
|
||||
updateThumbnailParam={handleThumbnailChange}
|
||||
/>
|
||||
<fieldset-section>
|
||||
<SelectThumbnail
|
||||
thumbnailParam={params.thumbnail_url}
|
||||
thumbnailParamError={params.thumbnail_error}
|
||||
thumbnailParamStatus={params.thumbnail_status}
|
||||
updateThumbnailParams={setParam}
|
||||
publishForm={false}
|
||||
/>
|
||||
</fieldset-section>
|
||||
<FormField
|
||||
type="markdown"
|
||||
name="content_description2"
|
||||
|
@ -436,7 +421,14 @@ function CollectionForm(props: Props) {
|
|||
<div className="section__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
disabled={creatingCollection || updatingCollection || nameError || bidError || !params.claims.length}
|
||||
disabled={
|
||||
creatingCollection ||
|
||||
updatingCollection ||
|
||||
nameError ||
|
||||
bidError ||
|
||||
thumbnailError ||
|
||||
!params.claims.length
|
||||
}
|
||||
label={creatingCollection || updatingCollection ? __('Submitting') : __('Submit')}
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
|
|
|
@ -46,10 +46,11 @@ function PublishFormErrors(props: Props) {
|
|||
{!bid && <div>{__('A deposit amount is required')}</div>}
|
||||
{bidError && <div>{__('Please check your deposit amount.')}</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>
|
||||
) : (
|
||||
thumbnailError && !thumbnailUploaded && <div>{__('Thumbnail is invalid.')}</div>
|
||||
)}
|
||||
{thumbnailError && !thumbnailUploaded && <div>{__('Thumbnail is invalid.')}</div>}
|
||||
{editingURI && !isStillEditing && !filePath && (
|
||||
<div>{__('Please reselect a file after changing the LBRY URL')}</div>
|
||||
)}
|
||||
|
|
|
@ -6,23 +6,19 @@ import {
|
|||
selectFileInfosByOutpoint,
|
||||
doResetThumbnailStatus,
|
||||
} from 'lbry-redux';
|
||||
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import PublishPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
const select = (state) => ({
|
||||
...selectPublishFormValues(state),
|
||||
fileInfos: selectFileInfosByOutpoint(state),
|
||||
myClaimForUri: selectMyClaimForUri(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
const perform = (dispatch) => ({
|
||||
updatePublishForm: (value) => dispatch(doUpdatePublishForm(value)),
|
||||
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(PublishPage);
|
||||
export default connect(select, perform)(PublishPage);
|
||||
|
|
|
@ -16,168 +16,181 @@ type Props = {
|
|||
thumbnail: ?string,
|
||||
formDisabled: boolean,
|
||||
uploadThumbnailStatus: string,
|
||||
publishForm: boolean,
|
||||
thumbnailPath: ?string,
|
||||
thumbnailError: ?string,
|
||||
thumbnailParam: ?string,
|
||||
thumbnailParamError: boolean,
|
||||
thumbnailParamStatus: string,
|
||||
openModal: (id: string, {}) => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
updateThumbnailParams: ({}) => void,
|
||||
resetThumbnailStatus: () => void,
|
||||
};
|
||||
|
||||
class SelectThumbnail extends React.PureComponent<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
(this: any).handleThumbnailChange = this.handleThumbnailChange.bind(this);
|
||||
function SelectThumbnail(props: Props) {
|
||||
const {
|
||||
filePath,
|
||||
fileInfos,
|
||||
myClaimForUri,
|
||||
formDisabled,
|
||||
publishForm = true,
|
||||
uploadThumbnailStatus: status,
|
||||
openModal,
|
||||
updatePublishForm,
|
||||
thumbnailParam,
|
||||
thumbnailParamStatus,
|
||||
updateThumbnailParams,
|
||||
thumbnailPath,
|
||||
resetThumbnailStatus,
|
||||
} = props;
|
||||
|
||||
const thumbnail = publishForm ? props.thumbnail : thumbnailParam;
|
||||
const thumbnailError = publishForm ? props.thumbnailError : props.thumbnailParamError;
|
||||
|
||||
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 fileInfo = outpoint ? fileInfos[outpoint] : undefined;
|
||||
const downloadPath = fileInfo ? fileInfo.download_path : undefined;
|
||||
|
||||
const actualFilePath = filePath || downloadPath;
|
||||
let isSupportedVideo = false;
|
||||
if (typeof actualFilePath === 'string') {
|
||||
isSupportedVideo = Lbry.getMediaType(null, actualFilePath) === 'video';
|
||||
} else if (actualFilePath && actualFilePath.type) {
|
||||
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
|
||||
}
|
||||
|
||||
handleThumbnailChange(e: SyntheticInputEvent<*>) {
|
||||
const { updatePublishForm } = this.props;
|
||||
function handleThumbnailChange(e: SyntheticInputEvent<*>) {
|
||||
const newThumbnail = e.target.value.replace(' ', '');
|
||||
|
||||
updatePublishForm({
|
||||
thumbnail: newThumbnail,
|
||||
thumbnailError: newThumbnail.startsWith('data:image'),
|
||||
});
|
||||
if (updateThumbnailParams) {
|
||||
updateThumbnailParams({ thumbnail_url: newThumbnail });
|
||||
} else {
|
||||
updatePublishForm({ thumbnail: newThumbnail });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
filePath,
|
||||
fileInfos,
|
||||
myClaimForUri,
|
||||
thumbnail,
|
||||
formDisabled,
|
||||
uploadThumbnailStatus: status,
|
||||
openModal,
|
||||
updatePublishForm,
|
||||
thumbnailPath,
|
||||
thumbnailError,
|
||||
resetThumbnailStatus,
|
||||
} = this.props;
|
||||
|
||||
const accept = '.png, .jpg, .jpeg, .gif';
|
||||
|
||||
const outpoint = myClaimForUri ? `${myClaimForUri.txid}:${myClaimForUri.nout}` : undefined;
|
||||
const fileInfo = outpoint ? fileInfos[outpoint] : undefined;
|
||||
const downloadPath = fileInfo ? fileInfo.download_path : undefined;
|
||||
|
||||
const actualFilePath = filePath || downloadPath;
|
||||
let isSupportedVideo = false;
|
||||
if (typeof actualFilePath === 'string') {
|
||||
isSupportedVideo = Lbry.getMediaType(null, actualFilePath) === 'video';
|
||||
} else if (actualFilePath && actualFilePath.type) {
|
||||
isSupportedVideo = actualFilePath.type.split('/')[0] === 'video';
|
||||
React.useEffect(() => {
|
||||
if (updateThumbnailParams && status !== thumbnailParamStatus) {
|
||||
updateThumbnailParams({ thumbnail_status: status });
|
||||
}
|
||||
}, [status, thumbnailParamStatus, updateThumbnailParams]);
|
||||
|
||||
let thumbnailInputSrc;
|
||||
if (!thumbnail) {
|
||||
thumbnailInputSrc = ThumbnailMissingImage;
|
||||
} else if (thumbnailError) {
|
||||
thumbnailInputSrc = ThumbnailBrokenImage;
|
||||
} else {
|
||||
thumbnailInputSrc = thumbnail;
|
||||
}
|
||||
let thumbnailSrc;
|
||||
if (!thumbnail) {
|
||||
thumbnailSrc = ThumbnailMissingImage;
|
||||
} else if (thumbnailError) {
|
||||
thumbnailSrc =
|
||||
(manualInput && ThumbnailBrokenImage) || (status !== THUMBNAIL_STATUSES.COMPLETE && ThumbnailMissingImage);
|
||||
} else {
|
||||
thumbnailSrc = thumbnail;
|
||||
}
|
||||
|
||||
/*
|
||||
Note:
|
||||
We are using backgroundImage instead of an <img /> to zoom if the selected thumbnail isn't
|
||||
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
|
||||
*/
|
||||
/*
|
||||
Note:
|
||||
We are using backgroundImage instead of an <img /> to zoom if the selected thumbnail isn't
|
||||
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
|
||||
*/
|
||||
const thumbPreview = (
|
||||
<div className="column__item thumbnail-picker__preview" style={{ backgroundImage: `url(${String(thumbnailSrc)})` }}>
|
||||
{thumbUploaded && thumbnailError !== false && __('This will be visible in a few minutes.')}
|
||||
<img
|
||||
style={{ display: 'none' }}
|
||||
src={thumbnail}
|
||||
alt={__('Thumbnail Preview')}
|
||||
onError={() =>
|
||||
publishForm
|
||||
? updatePublishForm({ thumbnailError: true })
|
||||
: updateThumbnailParams({ thumbnail_error: Boolean(thumbnail) })
|
||||
}
|
||||
onLoad={() =>
|
||||
publishForm
|
||||
? updatePublishForm({ thumbnailError: !isUrlInput })
|
||||
: updateThumbnailParams({ thumbnail_error: !isUrlInput })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
||||
<div className="column">
|
||||
<div className="column__item thumbnail-preview" style={{ backgroundImage: `url(${thumbnailInputSrc})` }}>
|
||||
<img
|
||||
style={{ display: 'none' }}
|
||||
src={thumbnailInputSrc}
|
||||
alt={__('Thumbnail Preview')}
|
||||
onError={() => updatePublishForm({ thumbnailError: true })}
|
||||
/>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
{status !== THUMBNAIL_STATUSES.IN_PROGRESS && (
|
||||
<div className="column">
|
||||
{thumbPreview}
|
||||
{publishForm && thumbUploaded ? (
|
||||
<div className="column__item">
|
||||
<FormField
|
||||
type="text"
|
||||
name="content_thumbnail"
|
||||
label="URL"
|
||||
placeholder="https://images.fbi.gov/alien"
|
||||
value={thumbnail}
|
||||
disabled={formDisabled}
|
||||
onChange={this.handleThumbnailChange}
|
||||
/>
|
||||
<p>{__('Upload complete.')}</p>
|
||||
<div className="section__actions">
|
||||
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="column__item">
|
||||
{manualInput ? (
|
||||
<FormField
|
||||
type="text"
|
||||
name="content_thumbnail"
|
||||
label="URL"
|
||||
placeholder="https://images.fbi.gov/alien"
|
||||
value={thumbnail}
|
||||
disabled={formDisabled}
|
||||
onChange={handleThumbnailChange}
|
||||
/>
|
||||
) : (
|
||||
<FileSelector
|
||||
currentPath={thumbnailPath}
|
||||
label={__('Thumbnail')}
|
||||
placeholder={__('Choose an enticing thumbnail')}
|
||||
accept={accept}
|
||||
onFileChosen={(file) =>
|
||||
openModal(MODALS.CONFIRM_THUMBNAIL_UPLOAD, {
|
||||
file,
|
||||
cb: (url) => !publishForm && updateThumbnailParams({ thumbnail_url: url }),
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Use thumbnail upload tool')}
|
||||
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.READY })}
|
||||
label={manualInput ? __('Use thumbnail upload tool') : __('Enter a thumbnail URL')}
|
||||
onClick={() =>
|
||||
updatePublishForm({
|
||||
uploadThumbnailStatus: manualInput ? THUMBNAIL_STATUSES.READY : THUMBNAIL_STATUSES.MANUAL,
|
||||
})
|
||||
}
|
||||
/>
|
||||
{status === THUMBNAIL_STATUSES.READY && isSupportedVideo && IS_WEB && (
|
||||
// Disabled on desktop until this is resolved
|
||||
// https://github.com/electron/electron/issues/20750#issuecomment-709505902
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Take a snapshot from your video')}
|
||||
onClick={() => openModal(MODALS.AUTO_GENERATE_THUMBNAIL, { filePath: actualFilePath })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
{status === THUMBNAIL_STATUSES.READY && (
|
||||
<FileSelector
|
||||
currentPath={thumbnailPath}
|
||||
label={__('Thumbnail')}
|
||||
placeholder={__('Choose an enticing thumbnail')}
|
||||
accept={accept}
|
||||
onFileChosen={(file) => openModal(MODALS.CONFIRM_THUMBNAIL_UPLOAD, { file })}
|
||||
/>
|
||||
)}
|
||||
{status === THUMBNAIL_STATUSES.COMPLETE && thumbnail && (
|
||||
<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="link"
|
||||
label={__('Enter a thumbnail URL')}
|
||||
onClick={() => updatePublishForm({ uploadThumbnailStatus: THUMBNAIL_STATUSES.MANUAL })}
|
||||
/>
|
||||
{isSupportedVideo && IS_WEB && (
|
||||
// Disabled on desktop until this is resolved
|
||||
// https://github.com/electron/electron/issues/20750#issuecomment-709505902
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Take a snapshot from your video')}
|
||||
onClick={() => openModal(MODALS.AUTO_GENERATE_THUMBNAIL, { filePath: actualFilePath })}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
|
||||
{status !== THUMBNAIL_STATUSES.COMPLETE && (
|
||||
<p className="help">
|
||||
{status === THUMBNAIL_STATUSES.API_DOWN
|
||||
? __('Enter a URL for your thumbnail.')
|
||||
: __('Upload your thumbnail to %domain%. Recommended size is 16:9.', { domain: DOMAIN })}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
|
||||
{!thumbUploaded && (
|
||||
<p className="help">
|
||||
{manualInput
|
||||
? __('Enter a URL for your thumbnail.')
|
||||
: __('Upload your thumbnail to %domain%. Recommended size is 16:9.', { domain: DOMAIN })}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectThumbnail;
|
||||
|
|
|
@ -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 |
|
@ -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;
|
|
@ -3,13 +3,10 @@ import { doHideModal } from 'redux/actions/app';
|
|||
import { doUploadThumbnail, doUpdatePublishForm } from 'lbry-redux';
|
||||
import ModalConfirmThumbnailUpload from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
const perform = (dispatch) => ({
|
||||
closeModal: () => dispatch(doHideModal()),
|
||||
upload: file => dispatch(doUploadThumbnail(null, file, null, null, file.path)),
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
upload: (file, cb) => dispatch(doUploadThumbnail(null, file, null, null, file.path, cb)),
|
||||
updatePublishForm: (value) => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
perform
|
||||
)(ModalConfirmThumbnailUpload);
|
||||
export default connect(null, perform)(ModalConfirmThumbnailUpload);
|
||||
|
|
|
@ -4,17 +4,18 @@ import { Modal } from 'modal/modal';
|
|||
import { DOMAIN } from 'config';
|
||||
|
||||
type Props = {
|
||||
upload: WebFile => void,
|
||||
file: WebFile,
|
||||
upload: (WebFile, (string) => void) => void,
|
||||
cb: (string) => void,
|
||||
closeModal: () => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
};
|
||||
|
||||
class ModalConfirmThumbnailUpload extends React.PureComponent<Props> {
|
||||
upload() {
|
||||
const { upload, updatePublishForm, closeModal, file } = this.props;
|
||||
const { upload, updatePublishForm, cb, closeModal, file } = this.props;
|
||||
if (file) {
|
||||
upload(file);
|
||||
upload(file, cb);
|
||||
updatePublishForm({ thumbnailPath: file.path });
|
||||
closeModal();
|
||||
}
|
||||
|
|
|
@ -10139,9 +10139,9 @@ lazy-val@^1.0.4:
|
|||
yargs "^13.2.2"
|
||||
zstd-codec "^0.1.1"
|
||||
|
||||
lbry-redux@lbryio/lbry-redux#372e559caee6af2b2d927e5d42419a71c3d15b57:
|
||||
lbry-redux@lbryio/lbry-redux#129b0ea3faa5da69ef1b85ea9ab7777b06aa3264:
|
||||
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:
|
||||
"@ungap/from-entries" "^0.2.1"
|
||||
proxy-polyfill "0.1.6"
|
||||
|
|
Loading…
Reference in a new issue