edit published content #32

Merged
akinwale merged 5 commits from edit-publish into master 2019-08-25 18:08:44 +02:00
11 changed files with 182 additions and 45 deletions
Showing only changes of commit 330997bc1e - Show all commits

6
package-lock.json generated
View file

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

View file

@ -22,7 +22,7 @@
"@react-native-community/async-storage": "^1.5.1",
"react-native-camera": "^2.11.1",
"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-fast-image": "^6.1.1",
"react-native-fs": "^2.13.3",

View file

@ -26,12 +26,19 @@ export default class ChannelSelector extends React.PureComponent {
}
componentDidMount() {
const { channels, fetchChannelListMine, fetchingChannels } = this.props;
const { channels, channelName, fetchChannelListMine, fetchingChannels } = this.props;
if (!channels.length && !fetchingChannels) {
fetchChannelListMine();
}
}
componentDidUpdate() {
const { channelName } = this.props;
if (this.state.currentSelectedValue !== channelName) {
this.setState({ currentSelectedValue: channelName });
}
}
handleCreateCancel = () => {
this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 });
};

View file

@ -135,9 +135,11 @@ class UriBar extends React.PureComponent {
render() {
const {
allowEdit,
belowOverlay,
navigation,
onExitSelectionMode,
onEditActionPressed,
onDeleteActionPressed,
query,
selectedItemCount,
@ -175,6 +177,19 @@ class UriBar extends React.PureComponent {
</View>
<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
style={uriBarStyle.actionTouchArea}
onPress={() => {

View file

@ -43,6 +43,7 @@ import thunk from 'redux-thunk';
const globalExceptionHandler = (error, isFatal) => {
if (error && NativeModules.Firebase) {
console.log(error);
NativeModules.Firebase.logException(isFatal, error.message ? error.message : 'No message', JSON.stringify(error));
}
};

View file

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

View file

@ -231,6 +231,11 @@ class FilePage extends React.PureComponent {
}
};
onEditPressed = () => {
const { claim, navigation } = this.props;
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH, params: { editMode: true, claimToEdit: claim } });
kauffj commented 2019-08-22 23:04:58 +02:00 (Migrated from github.com)
Review

would it make more sense to pass the claim id here rather than the whole object?

the publish component should be able to select the claim just from the id

would it make more sense to pass the claim id here rather than the whole object? the publish component should be able to select the claim just from the id
akinwale commented 2019-08-23 10:27:55 +02:00 (Migrated from github.com)
Review

This seemed easier to do since we only need a snapshot of the claim object, and it's less lines off code. Either way works.

This seemed easier to do since we only need a snapshot of the claim object, and it's less lines off code. Either way works.
};
onDeletePressed = () => {
const { claim, deleteFile, deletePurchasedUri, fileInfo, navigation } = this.props;
@ -243,11 +248,11 @@ class FilePage extends React.PureComponent {
text: 'Yes',
onPress: () => {
const { uri } = navigation.state.params;
deleteFile(`${claim.txid}:${claim.nout}`, true);
deletePurchasedUri(uri);
if (NativeModules.UtilityModule) {
NativeModules.UtilityModule.deleteDownload(uri);
}
NativeModules.UtilityModule.deleteDownload(uri);
this.setState({
downloadPressed: false,
fileViewLogged: false,
@ -568,6 +573,7 @@ class FilePage extends React.PureComponent {
rewardedContentClaimIds,
isResolvingUri,
blackListedOutpoints,
myClaimUris,
navigation,
position,
purchaseUri,
@ -640,19 +646,20 @@ class FilePage extends React.PureComponent {
const isPlayable = mediaType === 'video' || mediaType === 'audio';
const { height, signing_channel: signingChannel, value } = claim;
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 =
fileInfo &&
fileInfo.download_path &&
(canEdit || (fileInfo && fileInfo.download_path)) &&
!this.state.fullscreenMode &&
!this.state.showImageViewer &&
!this.state.showWebView;
const showFileActions =
fileInfo &&
fileInfo.download_path &&
(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}`;
canEdit ||
(fileInfo &&
fileInfo.download_path &&
(completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes)));
const fullChannelUri =
channelClaimId && channelClaimId.trim().length > 0
? normalizeURI(`${channelName}#${channelClaimId}`)
@ -823,6 +830,16 @@ class FilePage extends React.PureComponent {
<View style={filePageStyle.actions}>
{showFileActions && (
<View style={filePageStyle.fileActions}>
{canEdit && (
<Button
style={[filePageStyle.actionButton, filePageStyle.editButton]}
theme={'light'}
icon={'edit'}
text={'Edit'}
onPress={this.onEditPressed}
/>
)}
{completed && (
<Button
style={filePageStyle.actionButton}

View file

@ -18,15 +18,16 @@ import { FlatGrid } from 'react-native-super-grid';
import {
isNameValid,
buildURI,
normalizeURI,
regexInvalidURI,
CLAIM_VALUES,
LICENSES,
MATURE_TAGS,
THUMBNAIL_STATUSES,
} from 'lbry-redux';
import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker';
import { RNCamera } from 'react-native-camera';
import { generateCombination } from 'gfycat-style-urls';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';
import Button from 'component/button';
import ChannelSelector from 'component/channelSelector';
@ -77,6 +78,7 @@ class PublishPage extends React.PureComponent {
state = {
canUseCamera: false,
editMode: false,
titleFocused: false,
descriptionFocused: false,
loadingVideos: false,
@ -114,7 +116,6 @@ class PublishPage extends React.PureComponent {
license: LICENSES.NONE,
licenseUrl: '',
otherLicenseDescription: '',
mature: false,
name: null,
price: 0,
uri: null,
@ -158,7 +159,7 @@ class PublishPage extends React.PureComponent {
};
onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible } = this.props;
const { pushDrawerStack, setPlayerVisible, navigation } = this.props;
pushDrawerStack();
setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Publish');
@ -173,6 +174,69 @@ class PublishPage extends React.PureComponent {
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,
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) {
@ -209,6 +273,7 @@ class PublishPage extends React.PureComponent {
handlePublishPressed = () => {
const { notify, publish, updatePublishForm } = this.props;
const {
editMode,
bid,
channelName,
currentMedia,
@ -217,7 +282,6 @@ class PublishPage extends React.PureComponent {
license,
licenseUrl,
otherLicenseDescription,
mature,
name,
price,
priceSet,
@ -237,14 +301,21 @@ class PublishPage extends React.PureComponent {
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 = {
filePath: currentMedia.filePath,
filePath: currentMedia ? currentMedia.filePath : null,
bid: bid || 0.1,
title: title || '',
thumbnail,
description: description || '',
language,
license,
licenseType: license,
licenseUrl,
otherLicenseDescription,
name: name || undefined,
@ -253,12 +324,9 @@ class PublishPage extends React.PureComponent {
uri: uri || undefined,
channel: CLAIM_VALUES.CHANNEL_ANONYMOUS === channelName ? null : channelName,
isStillEditing: false,
claim: {
value: {
tags,
release_time: Math.round(Date.now() / 1000), // set now as the release time
},
},
tags: tags.map(tag => {
return { name: tag };
}),
};
updatePublishForm(publishParams);
@ -320,6 +388,7 @@ class PublishPage extends React.PureComponent {
this.setState(
{
publishStarted: false,
editMode: false,
currentMedia: null,
currentThumbnailUri: null,
@ -434,16 +503,16 @@ class PublishPage extends React.PureComponent {
};
handleUploadPressed = () => {
DocumentPicker.show(
{
filetype: [DocumentPickerUtil.allFiles()],
},
(error, res) => {
if (!error) {
// console.log(res);
DocumentPicker.pick({ type: [DocumentPicker.types.allFiles] })
.then(file => {
// console.log(file);
})
.catch(error => {
if (!DocumentPicker.isCancel(error)) {
// notify the user
// console.log(error);
}
}
);
});
};
getRandomFileId = () => {
@ -685,9 +754,12 @@ class PublishPage extends React.PureComponent {
)}
</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;
if (!currentThumbnailUri) {
if (!currentThumbnailUri && !this.state.editMode) {
this.updateThumbnailUriForMedia(currentMedia);
}
content = (
@ -764,7 +836,7 @@ class PublishPage extends React.PureComponent {
<View style={publishStyle.card}>
<Text style={publishStyle.cardTitle}>Channel</Text>
<ChannelSelector onChannelChange={this.handleChannelChange} />
<ChannelSelector channelName={this.state.channelName} onChannelChange={this.handleChannelChange} />
</View>
<View style={publishStyle.card}>
@ -798,11 +870,14 @@ class PublishPage extends React.PureComponent {
<View style={publishStyle.card}>
<Text style={publishStyle.cardTitle}>Content Address</Text>
<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>
<TextInput
placeholder={'lbry://'}
editable={!this.state.editMode}
style={publishStyle.inputText}
underlineColorAndroid={Colors.NextLbryGreen}
numberOfLines={1}
@ -902,7 +977,7 @@ class PublishPage extends React.PureComponent {
<Button
style={publishStyle.publishButton}
disabled={balance < 0.1 || !this.state.uploadedThumbnailUri}
text="Publish"
text={this.state.editMode ? 'Save changes' : 'Publish'}
onPress={this.handlePublishPressed}
/>
</View>

View file

@ -70,6 +70,16 @@ class PublishesPage extends React.PureComponent {
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 = () => {
const { abandonClaim } = this.props;
const { selectedClaimsMap } = this.state;
@ -103,11 +113,13 @@ class PublishesPage extends React.PureComponent {
return (
<View style={publishStyle.container}>
<UriBar
allowEdit
navigation={navigation}
selectionMode={selectionMode}
selectedItemCount={selectedUris.length}
onExitSelectionMode={this.onExitSelectionMode}
onDeleteActionPressed={this.onDeleteActionPressed}
onEditActionPressed={this.onEditActionPressed}
onExitSelectionMode={this.onExitSelectionMode}
/>
{fetching && (
<View style={publishStyle.centered}>
@ -138,7 +150,6 @@ class PublishesPage extends React.PureComponent {
removeClippedSubviews
renderItem={({ item }) => (
<FileListItem
hideChannel
key={item}
uri={item}
style={publishStyle.listItem}

View file

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

View file

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