Compare commits

...

5 commits

Author SHA1 Message Date
Akinwale Ariwodola
6e4765a743 fixes from ui/ux review 2019-08-25 17:07:50 +01:00
Akinwale Ariwodola
6217c45322 fix merge conflict and buildURI 2019-08-25 16:41:20 +01:00
Akinwale Ariwodola
dfb43199ea fix: error from clicking post-publish link 2019-08-22 16:31:13 +01:00
Akinwale Ariwodola
42488c0b39 remove console.log 2019-08-22 15:55:09 +01:00
Akinwale Ariwodola
330997bc1e edit published content 2019-08-22 15:51:57 +01:00
10 changed files with 244 additions and 73 deletions

6
package-lock.json generated
View file

@ -8046,9 +8046,9 @@
} }
}, },
"react-native-document-picker": { "react-native-document-picker": {
"version": "2.3.0", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-2.3.0.tgz", "resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-3.2.4.tgz",
"integrity": "sha512-bHMyAOzFl+II0ZdfzobKsZKvTErmXfmQGalpxpGbeN8+/uhfhUcdp4WuIMecZhFyX6rbj3h3XXLdA12hVlGgmw==" "integrity": "sha512-5l0/fkgasUZdIk9jUUkReDtNCQn2yg1+BrMPHMt45c/NVmE15ThnhIuDj8/n8h1F1RlhUb3SzF86ANK4OdZAiQ=="
}, },
"react-native-exception-handler": { "react-native-exception-handler": {
"version": "2.9.0", "version": "2.9.0",

View file

@ -22,7 +22,7 @@
"@react-native-community/async-storage": "^1.5.1", "@react-native-community/async-storage": "^1.5.1",
"react-native-camera": "^2.11.1", "react-native-camera": "^2.11.1",
"react-native-country-picker-modal": "^0.6.2", "react-native-country-picker-modal": "^0.6.2",
"react-native-document-picker": "^2.3.0", "react-native-document-picker": "^3.2.4",
"react-native-exception-handler": "2.9.0", "react-native-exception-handler": "2.9.0",
"react-native-fast-image": "^6.1.1", "react-native-fast-image": "^6.1.1",
"react-native-fs": "^2.13.3", "react-native-fs": "^2.13.3",

View file

@ -26,12 +26,19 @@ export default class ChannelSelector extends React.PureComponent {
} }
componentDidMount() { componentDidMount() {
const { channels, fetchChannelListMine, fetchingChannels } = this.props; const { channels, channelName, fetchChannelListMine, fetchingChannels } = this.props;
if (!channels.length && !fetchingChannels) { if (!channels.length && !fetchingChannels) {
fetchChannelListMine(); fetchChannelListMine();
} }
} }
componentDidUpdate() {
const { channelName } = this.props;
if (this.state.currentSelectedValue !== channelName) {
this.setState({ currentSelectedValue: channelName });
}
}
handleCreateCancel = () => { handleCreateCancel = () => {
this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 }); this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 });
}; };
@ -171,7 +178,7 @@ export default class ChannelSelector extends React.PureComponent {
render() { render() {
const channel = this.state.addingChannel ? 'new' : this.props.channel; const channel = this.state.addingChannel ? 'new' : this.props.channel;
const { fetchingChannels, channels = [] } = this.props; const { enabled, fetchingChannels, channels = [] } = this.props;
const pickerItems = [Constants.ITEM_ANONYMOUS, Constants.ITEM_CREATE_A_CHANNEL].concat(channels.map(ch => ch.name)); const pickerItems = [Constants.ITEM_ANONYMOUS, Constants.ITEM_CREATE_A_CHANNEL].concat(channels.map(ch => ch.name));
const { const {
@ -188,6 +195,7 @@ export default class ChannelSelector extends React.PureComponent {
return ( return (
<View style={channelSelectorStyle.container}> <View style={channelSelectorStyle.container}>
<Picker <Picker
enabled={enabled}
selectedValue={this.state.currentSelectedValue} selectedValue={this.state.currentSelectedValue}
style={channelSelectorStyle.channelPicker} style={channelSelectorStyle.channelPicker}
itemStyle={channelSelectorStyle.channelPickerItem} itemStyle={channelSelectorStyle.channelPickerItem}

View file

@ -135,9 +135,11 @@ class UriBar extends React.PureComponent {
render() { render() {
const { const {
allowEdit,
belowOverlay, belowOverlay,
navigation, navigation,
onExitSelectionMode, onExitSelectionMode,
onEditActionPressed,
onDeleteActionPressed, onDeleteActionPressed,
query, query,
selectedItemCount, selectedItemCount,
@ -175,6 +177,19 @@ class UriBar extends React.PureComponent {
</View> </View>
<View style={uriBarStyle.selectionModeActions}> <View style={uriBarStyle.selectionModeActions}>
{allowEdit && selectedItemCount === 1 && (
<TouchableOpacity
style={[uriBarStyle.actionTouchArea, uriBarStyle.leftAction]}
onPress={() => {
if (onEditActionPressed) {
onEditActionPressed();
}
}}
>
<Icon name="edit" size={20} style={uriBarStyle.actionIcon} />
</TouchableOpacity>
)}
<TouchableOpacity <TouchableOpacity
style={uriBarStyle.actionTouchArea} style={uriBarStyle.actionTouchArea}
onPress={() => { onPress={() => {

View file

@ -1,6 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
doFetchFileInfo, doFetchFileInfo,
doFetchClaimListMine,
doFileGet, doFileGet,
doPurchaseUri, doPurchaseUri,
doDeletePurchasedUri, doDeletePurchasedUri,
@ -18,6 +19,7 @@ import {
makeSelectThumbnailForUri, makeSelectThumbnailForUri,
makeSelectTitleForUri, makeSelectTitleForUri,
selectBalance, selectBalance,
selectMyClaimUrisWithoutChannels,
selectPurchasedUris, selectPurchasedUris,
selectFailedPurchaseUris, selectFailedPurchaseUris,
selectPurchaseUriErrorMessage, selectPurchaseUriErrorMessage,
@ -50,14 +52,15 @@ const select = (state, props) => {
contentType: makeSelectContentTypeForUri(selectProps.uri)(state), contentType: makeSelectContentTypeForUri(selectProps.uri)(state),
costInfo: makeSelectCostInfoForUri(selectProps.uri)(state), costInfo: makeSelectCostInfoForUri(selectProps.uri)(state),
metadata: makeSelectMetadataForUri(selectProps.uri)(state), metadata: makeSelectMetadataForUri(selectProps.uri)(state),
//obscureNsfw: !selectShowNsfw(state), // obscureNsfw: !selectShowNsfw(state),
//tab: makeSelectCurrentParam('tab')(state), // tab: makeSelectCurrentParam('tab')(state),
fileInfo: makeSelectFileInfoForUri(selectProps.uri)(state), fileInfo: makeSelectFileInfoForUri(selectProps.uri)(state),
rewardedContentClaimIds: selectRewardContentClaimIds(state, selectProps), rewardedContentClaimIds: selectRewardContentClaimIds(state, selectProps),
channelUri: makeSelectChannelForClaimUri(selectProps.uri, true)(state), channelUri: makeSelectChannelForClaimUri(selectProps.uri, true)(state),
position: makeSelectContentPositionForUri(selectProps.uri)(state), position: makeSelectContentPositionForUri(selectProps.uri)(state),
purchasedUris: selectPurchasedUris(state), purchasedUris: selectPurchasedUris(state),
failedPurchaseUris: selectFailedPurchaseUris(state), failedPurchaseUris: selectFailedPurchaseUris(state),
myClaimUris: selectMyClaimUrisWithoutChannels(state),
purchaseUriErrorMessage: selectPurchaseUriErrorMessage(state), purchaseUriErrorMessage: selectPurchaseUriErrorMessage(state),
streamingUrl: makeSelectStreamingUrlForUri(selectProps.uri)(state), streamingUrl: makeSelectStreamingUrlForUri(selectProps.uri)(state),
thumbnail: makeSelectThumbnailForUri(selectProps.uri)(state), thumbnail: makeSelectThumbnailForUri(selectProps.uri)(state),
@ -71,6 +74,7 @@ const perform = dispatch => ({
}, },
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)), fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)), fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
fetchMyClaims: () => dispatch(doFetchClaimListMine()),
fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)), fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)),
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
popDrawerStack: () => dispatch(doPopDrawerStack()), popDrawerStack: () => dispatch(doPopDrawerStack()),

View file

@ -232,6 +232,11 @@ class FilePage extends React.PureComponent {
} }
}; };
onEditPressed = () => {
const { claim, navigation } = this.props;
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH, params: { editMode: true, claimToEdit: claim } });
};
onDeletePressed = () => { onDeletePressed = () => {
const { claim, deleteFile, deletePurchasedUri, fileInfo, navigation } = this.props; const { claim, deleteFile, deletePurchasedUri, fileInfo, navigation } = this.props;
@ -244,11 +249,11 @@ class FilePage extends React.PureComponent {
text: 'Yes', text: 'Yes',
onPress: () => { onPress: () => {
const { uri } = navigation.state.params; const { uri } = navigation.state.params;
deleteFile(`${claim.txid}:${claim.nout}`, true); deleteFile(`${claim.txid}:${claim.nout}`, true);
deletePurchasedUri(uri); deletePurchasedUri(uri);
if (NativeModules.UtilityModule) {
NativeModules.UtilityModule.deleteDownload(uri); NativeModules.UtilityModule.deleteDownload(uri);
}
this.setState({ this.setState({
downloadPressed: false, downloadPressed: false,
fileViewLogged: false, fileViewLogged: false,
@ -571,6 +576,7 @@ class FilePage extends React.PureComponent {
rewardedContentClaimIds, rewardedContentClaimIds,
isResolvingUri, isResolvingUri,
blackListedOutpoints, blackListedOutpoints,
myClaimUris,
navigation, navigation,
position, position,
purchaseUri, purchaseUri,
@ -643,19 +649,20 @@ class FilePage extends React.PureComponent {
const isPlayable = mediaType === 'video' || mediaType === 'audio'; const isPlayable = mediaType === 'video' || mediaType === 'audio';
const { height, signing_channel: signingChannel, value } = claim; const { height, signing_channel: signingChannel, value } = claim;
const channelName = signingChannel && signingChannel.name; const channelName = signingChannel && signingChannel.name;
const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id;
const canSendTip = this.state.tipAmount > 0;
const fullUri = `${claim.name}#${claim.claim_id}`;
const canEdit = myClaimUris.includes(normalizeURI(fullUri));
const showActions = const showActions =
fileInfo && (canEdit || (fileInfo && fileInfo.download_path)) &&
fileInfo.download_path &&
!this.state.fullscreenMode && !this.state.fullscreenMode &&
!this.state.showImageViewer && !this.state.showImageViewer &&
!this.state.showWebView; !this.state.showWebView;
const showFileActions = const showFileActions =
fileInfo && canEdit ||
(fileInfo &&
fileInfo.download_path && fileInfo.download_path &&
(completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes)); (completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes)));
const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id;
const canSendTip = this.state.tipAmount > 0;
const fullUri = `${claim.name}#${claim.claim_id}`;
const fullChannelUri = const fullChannelUri =
channelClaimId && channelClaimId.trim().length > 0 channelClaimId && channelClaimId.trim().length > 0
? normalizeURI(`${channelName}#${channelClaimId}`) ? normalizeURI(`${channelName}#${channelClaimId}`)
@ -826,6 +833,16 @@ class FilePage extends React.PureComponent {
<View style={filePageStyle.actions}> <View style={filePageStyle.actions}>
{showFileActions && ( {showFileActions && (
<View style={filePageStyle.fileActions}> <View style={filePageStyle.fileActions}>
{canEdit && (
<Button
style={[filePageStyle.actionButton, filePageStyle.editButton]}
theme={'light'}
icon={'edit'}
text={'Edit'}
onPress={this.onEditPressed}
/>
)}
{completed && ( {completed && (
<Button <Button
style={filePageStyle.actionButton} style={filePageStyle.actionButton}

View file

@ -18,15 +18,16 @@ import { FlatGrid } from 'react-native-super-grid';
import { import {
isNameValid, isNameValid,
buildURI, buildURI,
normalizeURI,
regexInvalidURI, regexInvalidURI,
CLAIM_VALUES, CLAIM_VALUES,
LICENSES, LICENSES,
MATURE_TAGS, MATURE_TAGS,
THUMBNAIL_STATUSES, THUMBNAIL_STATUSES,
} from 'lbry-redux'; } from 'lbry-redux';
import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker';
import { RNCamera } from 'react-native-camera'; import { RNCamera } from 'react-native-camera';
import { generateCombination } from 'gfycat-style-urls'; import { generateCombination } from 'gfycat-style-urls';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs'; import RNFS from 'react-native-fs';
import Button from 'component/button'; import Button from 'component/button';
import ChannelSelector from 'component/channelSelector'; import ChannelSelector from 'component/channelSelector';
@ -42,7 +43,7 @@ import Tag from 'component/tag';
import TagSearch from 'component/tagSearch'; import TagSearch from 'component/tagSearch';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import publishStyle from 'styles/publish'; import publishStyle from 'styles/publish';
import __ from 'utils/helper'; import { __, navigateToUri } from 'utils/helper';
const languages = { const languages = {
en: 'English', en: 'English',
@ -76,7 +77,9 @@ class PublishPage extends React.PureComponent {
camera = null; camera = null;
state = { state = {
canPublish: false,
canUseCamera: false, canUseCamera: false,
editMode: false,
titleFocused: false, titleFocused: false,
descriptionFocused: false, descriptionFocused: false,
loadingVideos: false, loadingVideos: false,
@ -107,6 +110,7 @@ class PublishPage extends React.PureComponent {
priceSet: false, priceSet: false,
// input data // input data
hasEditedContentAddress: false,
bid: 0.1, bid: 0.1,
description: null, description: null,
title: null, title: null,
@ -114,7 +118,6 @@ class PublishPage extends React.PureComponent {
license: LICENSES.NONE, license: LICENSES.NONE,
licenseUrl: '', licenseUrl: '',
otherLicenseDescription: '', otherLicenseDescription: '',
mature: false,
name: null, name: null,
price: 0, price: 0,
uri: null, uri: null,
@ -158,23 +161,89 @@ class PublishPage extends React.PureComponent {
}; };
onComponentFocused = () => { onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible } = this.props; const { balance, pushDrawerStack, setPlayerVisible, navigation } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('New publish').then(result => {
NativeModules.Firebase.setCurrentScreen('Publish').then(result => {
NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera })); NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera }));
NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath })); NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath }));
this.setState( this.setState(
{ {
canPublish: balance >= 0.1,
loadingVideos: true, loadingVideos: true,
}, },
() => { () => {
NativeModules.Gallery.getVideos().then(videos => this.setState({ videos, loadingVideos: false })); NativeModules.Gallery.getVideos().then(videos => this.setState({ videos, loadingVideos: false }));
} }
); );
// Check if this is an edit action
if (navigation.state.params) {
const { editMode, claimToEdit } = navigation.state.params;
if (editMode) {
this.prepareEdit(claimToEdit);
}
}
}); });
}; };
prepareEdit = claim => {
let channelName;
const { amount, name, signing_channel: signingChannel, value } = claim;
const { description, fee, languages, license, license_url: licenseUrl, tags, thumbnail, title } = value;
if (signingChannel) {
channelName = signingChannel.name;
}
const thumbnailUrl = thumbnail ? thumbnail.url : null;
// Determine the license
let licenseType, otherLicenseDescription;
if (!LICENSES.CC_LICENSES.some(({ value }) => value === license)) {
if (!license || license === LICENSES.NONE || license === LICENSES.PUBLIC_DOMAIN) {
licenseType = license;
} else if (license && !licenseUrl && license !== LICENSES.NONE) {
licenseType = LICENSES.COPYRIGHT;
} else {
licenseType = LICENSES.OTHER;
}
otherLicenseDescription = license;
} else {
licenseType = license;
}
this.setState(
{
editMode: true,
currentPhase: Constants.PHASE_DETAILS,
hasEditedContentAddress: true,
bid: amount,
channelName,
description,
language: languages && languages.length > 0 ? languages[0] : 'en', // default to English
license: licenseType,
licenseUrl,
otherLicenseDescription,
name,
price: fee && fee.amount ? fee.amount : 0,
priceSet: fee && fee.amount > 0,
tags: tags && tags.length > 0 ? tags : [],
title,
currentThumbnailUri: thumbnailUrl,
uploadedThumbnailUri: thumbnailUrl,
},
() => {
this.handleNameChange(name);
if (channelName) {
this.handleChannelChange(channelName);
}
}
);
};
getNewUri(name, channel) { getNewUri(name, channel) {
const { resolveUri } = this.props; const { resolveUri } = this.props;
// If they are midway through a channel creation, treat it as anonymous until it completes // If they are midway through a channel creation, treat it as anonymous until it completes
@ -184,7 +253,7 @@ class PublishPage extends React.PureComponent {
// We are only going to store the full uri, but we need to resolve the uri with and without the channel name // We are only going to store the full uri, but we need to resolve the uri with and without the channel name
let uri; let uri;
try { try {
uri = buildURI({ contentName: name, channelName }); uri = buildURI({ claimName: name, channelName });
} catch (e) { } catch (e) {
// something wrong with channel or name // something wrong with channel or name
} }
@ -192,7 +261,7 @@ class PublishPage extends React.PureComponent {
if (uri) { if (uri) {
if (channelName) { if (channelName) {
// resolve without the channel name so we know the winning bid for it // resolve without the channel name so we know the winning bid for it
const uriLessChannel = buildURI({ contentName: name }); const uriLessChannel = buildURI({ claimName: name });
resolveUri(uriLessChannel); resolveUri(uriLessChannel);
} }
resolveUri(uri); resolveUri(uri);
@ -209,6 +278,7 @@ class PublishPage extends React.PureComponent {
handlePublishPressed = () => { handlePublishPressed = () => {
const { notify, publish, updatePublishForm } = this.props; const { notify, publish, updatePublishForm } = this.props;
const { const {
editMode,
bid, bid,
channelName, channelName,
currentMedia, currentMedia,
@ -217,7 +287,6 @@ class PublishPage extends React.PureComponent {
license, license,
licenseUrl, licenseUrl,
otherLicenseDescription, otherLicenseDescription,
mature,
name, name,
price, price,
priceSet, priceSet,
@ -237,14 +306,21 @@ class PublishPage extends React.PureComponent {
return; return;
} }
if (!currentMedia && !editMode) {
// sanity check. normally shouldn't happen
notify({ message: 'No file selected. Please select a video or take a photo before publishing.' });
return;
}
const publishParams = { const publishParams = {
filePath: currentMedia.filePath, filePath: currentMedia ? currentMedia.filePath : null,
bid: bid || 0.1, bid: bid || 0.1,
title: title || '', title: title || '',
thumbnail, thumbnail,
description: description || '', description: description || '',
language, language,
license, license,
licenseType: license,
licenseUrl, licenseUrl,
otherLicenseDescription, otherLicenseDescription,
name: name || undefined, name: name || undefined,
@ -253,12 +329,9 @@ class PublishPage extends React.PureComponent {
uri: uri || undefined, uri: uri || undefined,
channel: CLAIM_VALUES.CHANNEL_ANONYMOUS === channelName ? null : channelName, channel: CLAIM_VALUES.CHANNEL_ANONYMOUS === channelName ? null : channelName,
isStillEditing: false, isStillEditing: false,
claim: { tags: tags.map(tag => {
value: { return { name: tag };
tags, }),
release_time: Math.round(Date.now() / 1000), // set now as the release time
},
},
}; };
updatePublishForm(publishParams); updatePublishForm(publishParams);
@ -266,7 +339,11 @@ class PublishPage extends React.PureComponent {
}; };
handlePublishSuccess = data => { handlePublishSuccess = data => {
this.setState({ publishStarted: false, currentPhase: Constants.PHASE_PUBLISH }); const { navigation, notify } = this.props;
notify({
message: `Your content was successfully published to ${this.state.uri}. It will be available in a few mintues.`,
});
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISHES, params: { publishSuccess: true } });
}; };
handlePublishFailure = error => { handlePublishFailure = error => {
@ -302,7 +379,7 @@ class PublishPage extends React.PureComponent {
this.setState( this.setState(
{ {
currentMedia: media, currentMedia: media,
title: name, title: null, // no title autogeneration (user will fill this in)
name: this.formatNameForTitle(name), name: this.formatNameForTitle(name),
currentPhase: Constants.PHASE_DETAILS, currentPhase: Constants.PHASE_DETAILS,
}, },
@ -320,6 +397,7 @@ class PublishPage extends React.PureComponent {
this.setState( this.setState(
{ {
publishStarted: false, publishStarted: false,
editMode: false,
currentMedia: null, currentMedia: null,
currentThumbnailUri: null, currentThumbnailUri: null,
@ -334,6 +412,7 @@ class PublishPage extends React.PureComponent {
priceSet: false, priceSet: false,
// input data // input data
hasEditedContentAddress: false,
bid: 0.1, bid: 0.1,
description: null, description: null,
title: null, title: null,
@ -434,16 +513,16 @@ class PublishPage extends React.PureComponent {
}; };
handleUploadPressed = () => { handleUploadPressed = () => {
DocumentPicker.show( DocumentPicker.pick({ type: [DocumentPicker.types.allFiles] })
{ .then(file => {
filetype: [DocumentPickerUtil.allFiles()], // console.log(file);
}, })
(error, res) => { .catch(error => {
if (!error) { if (!DocumentPicker.isCancel(error)) {
// console.log(res); // notify the user
// console.log(error);
} }
} });
);
}; };
getRandomFileId = () => { getRandomFileId = () => {
@ -464,9 +543,13 @@ class PublishPage extends React.PureComponent {
this.setState({ price }); this.setState({ price });
}; };
handleNameChange = name => { handleNameChange = (name, userInput) => {
const { notify } = this.props; const { notify } = this.props;
this.setState({ name }); this.setState({ name });
if (userInput) {
this.setState({ hasEditedContentAddress: true });
}
if (!isNameValid(name, false)) { if (!isNameValid(name, false)) {
notify({ message: 'Your content address contains invalid characters' }); notify({ message: 'Your content address contains invalid characters' });
return; return;
@ -483,7 +566,7 @@ class PublishPage extends React.PureComponent {
}; };
handleAddTag = tag => { handleAddTag = tag => {
if (!tag) { if (!tag || !this.state.canPublish || this.state.publishStarted) {
return; return;
} }
@ -500,7 +583,7 @@ class PublishPage extends React.PureComponent {
}; };
handleRemoveTag = tag => { handleRemoveTag = tag => {
if (!tag) { if (!tag || !this.state.canPublish || this.state.publishStarted) {
return; return;
} }
@ -556,15 +639,20 @@ class PublishPage extends React.PureComponent {
}; };
handleTitleChange = title => { handleTitleChange = title => {
this.setState({ title });
if (!this.state.editMode && !this.state.hasEditedContentAddress) {
// only autogenerate url if the user has not yet edited the field
// also shouldn't change url in edit mode
this.setState( this.setState(
{ {
title,
name: this.formatNameForTitle(title), name: this.formatNameForTitle(title),
}, },
() => { () => {
this.handleNameChange(this.state.name); this.handleNameChange(this.state.name);
} }
); );
}
}; };
handleDescriptionChange = description => { handleDescriptionChange = description => {
@ -685,9 +773,12 @@ class PublishPage extends React.PureComponent {
)} )}
</View> </View>
); );
} else if (Constants.PHASE_DETAILS === this.state.currentPhase && this.state.currentMedia) { } else if (
Constants.PHASE_DETAILS === this.state.currentPhase &&
(this.state.editMode || this.state.currentMedia)
) {
const { currentMedia, currentThumbnailUri } = this.state; const { currentMedia, currentThumbnailUri } = this.state;
if (!currentThumbnailUri) { if (!currentThumbnailUri && !this.state.editMode) {
this.updateThumbnailUriForMedia(currentMedia); this.updateThumbnailUriForMedia(currentMedia);
} }
content = ( content = (
@ -701,7 +792,7 @@ class PublishPage extends React.PureComponent {
/> />
</View> </View>
)} )}
{balance < 0.1 && <PublishRewardsDriver navigation={navigation} />} {!this.state.canPublish && <PublishRewardsDriver navigation={navigation} />}
{this.state.uploadThumbnailStarted && !this.state.uploadedThumbnailUri && ( {this.state.uploadThumbnailStarted && !this.state.uploadedThumbnailUri && (
<View style={publishStyle.thumbnailUploadContainer}> <View style={publishStyle.thumbnailUploadContainer}>
@ -716,6 +807,7 @@ class PublishPage extends React.PureComponent {
<Text style={publishStyle.textInputTitle}>Title</Text> <Text style={publishStyle.textInputTitle}>Title</Text>
)} )}
<TextInput <TextInput
editable={this.state.canPublish && !this.state.publishStarted}
placeholder={this.state.titleFocused ? '' : 'Title'} placeholder={this.state.titleFocused ? '' : 'Title'}
style={publishStyle.inputText} style={publishStyle.inputText}
value={this.state.title} value={this.state.title}
@ -733,6 +825,7 @@ class PublishPage extends React.PureComponent {
<Text style={publishStyle.textInputTitle}>Description</Text> <Text style={publishStyle.textInputTitle}>Description</Text>
)} )}
<TextInput <TextInput
editable={this.state.canPublish && !this.state.publishStarted}
placeholder={this.state.descriptionFocused ? '' : 'Description'} placeholder={this.state.descriptionFocused ? '' : 'Description'}
style={publishStyle.inputText} style={publishStyle.inputText}
value={this.state.description} value={this.state.description}
@ -764,7 +857,11 @@ class PublishPage extends React.PureComponent {
<View style={publishStyle.card}> <View style={publishStyle.card}>
<Text style={publishStyle.cardTitle}>Channel</Text> <Text style={publishStyle.cardTitle}>Channel</Text>
<ChannelSelector onChannelChange={this.handleChannelChange} /> <ChannelSelector
enabled={this.state.canPublish && !this.state.publishStarted}
channelName={this.state.channelName}
onChannelChange={this.handleChannelChange}
/>
</View> </View>
<View style={publishStyle.card}> <View style={publishStyle.card}>
@ -782,6 +879,7 @@ class PublishPage extends React.PureComponent {
{this.state.priceSet && ( {this.state.priceSet && (
<View style={[publishStyle.inputRow, publishStyle.priceInputRow]}> <View style={[publishStyle.inputRow, publishStyle.priceInputRow]}>
<TextInput <TextInput
editable={this.state.canPublish && !this.state.publishStarted}
placeholder={'0.00'} placeholder={'0.00'}
keyboardType={'number-pad'} keyboardType={'number-pad'}
style={publishStyle.priceInput} style={publishStyle.priceInput}
@ -796,21 +894,25 @@ class PublishPage extends React.PureComponent {
</View> </View>
<View style={publishStyle.card}> <View style={publishStyle.card}>
<Text style={publishStyle.cardTitle}>Content Address</Text> <Text style={publishStyle.cardTitle}>Content address</Text>
<Text style={publishStyle.helpText}> <Text style={publishStyle.helpText}>
The address where people can find your content (ex. lbry://myvideo) The address where people can find your content (ex. lbry://myvideo).
{this.state.editMode &&
' You cannot change this address while editing your content. If you wish to use a new address, please republish the content.'}
</Text> </Text>
<TextInput <TextInput
editable={!this.state.editMode && this.state.canPublish && !this.state.publishStarted}
placeholder={'lbry://'} placeholder={'lbry://'}
style={publishStyle.inputText} style={publishStyle.inputText}
underlineColorAndroid={Colors.NextLbryGreen} underlineColorAndroid={Colors.NextLbryGreen}
numberOfLines={1} numberOfLines={1}
value={this.state.name} value={this.state.name}
onChangeText={this.handleNameChange} onChangeText={value => this.handleNameChange(value, true)}
/> />
<View style={publishStyle.inputRow}> <View style={publishStyle.inputRow}>
<TextInput <TextInput
editable={this.state.canPublish && !this.state.publishStarted}
placeholder={'0.00'} placeholder={'0.00'}
style={publishStyle.priceInput} style={publishStyle.priceInput}
underlineColorAndroid={Colors.NextLbryGreen} underlineColorAndroid={Colors.NextLbryGreen}
@ -830,6 +932,7 @@ class PublishPage extends React.PureComponent {
<View> <View>
<Text style={publishStyle.cardText}>Language</Text> <Text style={publishStyle.cardText}>Language</Text>
<Picker <Picker
enabled={this.state.canPublish && !this.state.publishStarted}
selectedValue={this.state.language} selectedValue={this.state.language}
style={publishStyle.picker} style={publishStyle.picker}
itemStyle={publishStyle.pickerItem} itemStyle={publishStyle.pickerItem}
@ -844,6 +947,7 @@ class PublishPage extends React.PureComponent {
<View> <View>
<Text style={publishStyle.cardText}>License</Text> <Text style={publishStyle.cardText}>License</Text>
<Picker <Picker
enabled={this.state.canPublish && !this.state.publishStarted}
selectedValue={this.state.license} selectedValue={this.state.license}
style={publishStyle.picker} style={publishStyle.picker}
itemStyle={publishStyle.pickerItem} itemStyle={publishStyle.pickerItem}
@ -859,6 +963,7 @@ class PublishPage extends React.PureComponent {
</Picker> </Picker>
{[LICENSES.COPYRIGHT, LICENSES.OTHER].includes(this.state.license) && ( {[LICENSES.COPYRIGHT, LICENSES.OTHER].includes(this.state.license) && (
<TextInput <TextInput
editable={this.state.canPublish && !this.state.publishStarted}
placeholder={'License description'} placeholder={'License description'}
style={publishStyle.inputText} style={publishStyle.inputText}
underlineColorAndroid={Colors.NextLbryGreen} underlineColorAndroid={Colors.NextLbryGreen}
@ -901,8 +1006,8 @@ class PublishPage extends React.PureComponent {
<View style={publishStyle.rightActionButtons}> <View style={publishStyle.rightActionButtons}>
<Button <Button
style={publishStyle.publishButton} style={publishStyle.publishButton}
disabled={balance < 0.1 || !this.state.uploadedThumbnailUri} disabled={!this.state.canPublish || !this.state.uploadedThumbnailUri}
text="Publish" text={this.state.editMode ? 'Save changes' : 'Publish'}
onPress={this.handlePublishPressed} onPress={this.handlePublishPressed}
/> />
</View> </View>
@ -917,7 +1022,11 @@ class PublishPage extends React.PureComponent {
<Text style={publishStyle.successTitle}>Success!</Text> <Text style={publishStyle.successTitle}>Success!</Text>
<Text style={publishStyle.successText}>Congratulations! Your content was successfully uploaded.</Text> <Text style={publishStyle.successText}>Congratulations! Your content was successfully uploaded.</Text>
<View style={publishStyle.successRow}> <View style={publishStyle.successRow}>
<Link style={publishStyle.successUrl} text={this.state.uri} href={this.state.uri} /> <Link
style={publishStyle.successUrl}
text={this.state.uri}
onPress={() => navigateToUri(navigation, this.state.uri)}
/>
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
Clipboard.setString(this.state.uri); Clipboard.setString(this.state.uri);

View file

@ -37,10 +37,10 @@ class PublishesPage extends React.PureComponent {
const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props; const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Publishes'); NativeModules.Firebase.setCurrentScreen('Publishes').then(result => {
fetchMyClaims(); fetchMyClaims();
checkPendingPublishes(); checkPendingPublishes();
});
}; };
addOrRemoveItem = (uri, claim) => { addOrRemoveItem = (uri, claim) => {
@ -70,6 +70,16 @@ class PublishesPage extends React.PureComponent {
this.setState({ selectionMode: false, selectedUris: [], selectedClaimsMap: {} }); this.setState({ selectionMode: false, selectedUris: [], selectedClaimsMap: {} });
}; };
onEditActionPressed = () => {
const { navigation } = this.props;
const { selectedClaimsMap, selectedUris } = this.state;
// only 1 item can be edited (and edit button should be visible only if there is a single selection)
const claim = selectedClaimsMap[selectedUris[0]];
this.onExitSelectionMode();
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH, params: { editMode: true, claimToEdit: claim } });
};
onDeleteActionPressed = () => { onDeleteActionPressed = () => {
const { abandonClaim } = this.props; const { abandonClaim } = this.props;
const { selectedClaimsMap } = this.state; const { selectedClaimsMap } = this.state;
@ -103,11 +113,13 @@ class PublishesPage extends React.PureComponent {
return ( return (
<View style={publishStyle.container}> <View style={publishStyle.container}>
<UriBar <UriBar
allowEdit
navigation={navigation} navigation={navigation}
selectionMode={selectionMode} selectionMode={selectionMode}
selectedItemCount={selectedUris.length} selectedItemCount={selectedUris.length}
onExitSelectionMode={this.onExitSelectionMode}
onDeleteActionPressed={this.onDeleteActionPressed} onDeleteActionPressed={this.onDeleteActionPressed}
onEditActionPressed={this.onEditActionPressed}
onExitSelectionMode={this.onExitSelectionMode}
/> />
{fetching && ( {fetching && (
<View style={publishStyle.centered}> <View style={publishStyle.centered}>
@ -138,7 +150,6 @@ class PublishesPage extends React.PureComponent {
removeClippedSubviews removeClippedSubviews
renderItem={({ item }) => ( renderItem={({ item }) => (
<FileListItem <FileListItem
hideChannel
key={item} key={item}
uri={item} uri={item}
style={publishStyle.listItem} style={publishStyle.listItem}

View file

@ -194,6 +194,10 @@ const filePageStyle = StyleSheet.create({
}, },
fileActions: { fileActions: {
alignSelf: 'flex-end', alignSelf: 'flex-end',
flexDirection: 'row',
},
editButton: {
marginRight: 8,
}, },
socialActions: { socialActions: {
alignSelf: 'flex-start', alignSelf: 'flex-start',

View file

@ -98,6 +98,9 @@ const uriBarStyle = StyleSheet.create({
height: '100%', height: '100%',
alignItems: 'center', alignItems: 'center',
}, },
leftAction: {
marginRight: 16,
},
actionTouchArea: { actionTouchArea: {
height: '100%', height: '100%',
alignItems: 'center', alignItems: 'center',