channel creator updates
This commit is contained in:
parent
563a9135ce
commit
f02fdd9979
11 changed files with 157 additions and 56 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -5574,8 +5574,8 @@
|
|||
}
|
||||
},
|
||||
"lbry-redux": {
|
||||
"version": "github:lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
|
||||
"from": "github:lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
|
||||
"version": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
|
||||
"from": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
|
||||
"requires": {
|
||||
"proxy-polyfill": "0.1.6",
|
||||
"reselect": "^3.0.0",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"base-64": "^0.1.0",
|
||||
"@expo/vector-icons": "^8.1.0",
|
||||
"gfycat-style-urls": "^1.0.3",
|
||||
"lbry-redux": "lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
|
||||
"lbry-redux": "lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
|
||||
"lbryinc": "lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4",
|
||||
"lodash": ">=4.17.11",
|
||||
"merge": ">=1.2.1",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doFetchClaimsByChannel, makeSelectClaimForUri } from 'lbry-redux';
|
||||
import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
|
||||
import { doPopDrawerStack } from 'redux/actions/drawer';
|
||||
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
|
||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||
|
@ -7,6 +7,7 @@ import { selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
|
|||
import ChannelPage from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
channels: selectMyChannelClaims(state),
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
drawerStack: selectDrawerStack(state),
|
||||
sortByItem: selectSortByItem(state),
|
||||
|
@ -14,7 +15,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||
popDrawerStack: () => dispatch(doPopDrawerStack()),
|
||||
setSortByItem: item => dispatch(doSetSortByItem(item)),
|
||||
setTimeItem: item => dispatch(doSetTimeItem(item)),
|
||||
|
|
|
@ -159,10 +159,22 @@ class ChannelPage extends React.PureComponent {
|
|||
);
|
||||
};
|
||||
|
||||
onEditPressed = () => {
|
||||
const { claim, navigation } = this.props;
|
||||
if (claim) {
|
||||
const { permanent_url: permanentUrl } = claim;
|
||||
navigation.navigate({
|
||||
routeName: Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
|
||||
params: { editChannelUrl: permanentUrl },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { claim, navigation, uri, drawerStack, popDrawerStack, sortByItem, timeItem } = this.props;
|
||||
const { channels, claim, navigation, uri, drawerStack, popDrawerStack, sortByItem, timeItem } = this.props;
|
||||
const { name, permanent_url: permanentUrl } = claim;
|
||||
const { autoStyle, showSortPicker, showTimePicker } = this.state;
|
||||
const ownedChannel = channels ? channels.map(channel => channel.permanent_url).includes(permanentUrl) : false;
|
||||
|
||||
let thumbnailUrl,
|
||||
coverUrl,
|
||||
|
@ -218,12 +230,23 @@ class ChannelPage extends React.PureComponent {
|
|||
</View>
|
||||
|
||||
<View style={channelPageStyle.subscribeButtonContainer}>
|
||||
<SubscribeButton style={channelPageStyle.subscribeButton} uri={fullUri} name={name} />
|
||||
{ownedChannel && (
|
||||
<Button
|
||||
style={channelPageStyle.actionButton}
|
||||
theme={'light'}
|
||||
icon={'edit'}
|
||||
text={'Edit'}
|
||||
onPress={this.onEditPressed}
|
||||
/>
|
||||
)}
|
||||
{!ownedChannel && <SubscribeButton style={channelPageStyle.subscribeButton} uri={fullUri} name={name} />}
|
||||
{!ownedChannel && (
|
||||
<SubscribeNotificationButton
|
||||
style={[channelPageStyle.subscribeButton, channelPageStyle.bellButton]}
|
||||
uri={fullUri}
|
||||
name={name}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
|
|
@ -42,12 +42,13 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
newChannelBid: 0.1,
|
||||
addingChannel: false,
|
||||
creatingChannel: false,
|
||||
editChannelUrl: null,
|
||||
newChannelNameError: '',
|
||||
newChannelBidError: '',
|
||||
createChannelError: undefined,
|
||||
showCreateChannel: false,
|
||||
thumbnailUrl: null,
|
||||
coverImageUrl: null,
|
||||
thumbnailUrl: '',
|
||||
coverImageUrl: '',
|
||||
|
||||
avatarImagePickerOpen: false,
|
||||
coverImagePickerOpen: false,
|
||||
|
@ -132,9 +133,11 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
fetchChannelListMine,
|
||||
fetchClaimListMine,
|
||||
fetchingChannels,
|
||||
navigation,
|
||||
pushDrawerStack,
|
||||
setPlayerVisible,
|
||||
} = this.props;
|
||||
|
||||
NativeModules.Firebase.setCurrentScreen('Channels').then(result => {
|
||||
pushDrawerStack();
|
||||
setPlayerVisible();
|
||||
|
@ -147,6 +150,11 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
|
||||
DeviceEventEmitter.addListener('onDocumentPickerFilePicked', this.onFilePicked);
|
||||
DeviceEventEmitter.addListener('onDocumentPickerCanceled', this.onPickerCanceled);
|
||||
|
||||
if (navigation.state.params) {
|
||||
const { editChannelUrl } = navigation.state.params;
|
||||
this.setState({ editChannelUrl });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -161,15 +169,18 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
// check which image we're trying to upload
|
||||
// should only be one or the other, so just default to cover
|
||||
const isCover = this.state.coverImagePickerOpen;
|
||||
const fileUrl = `file://${evt.path}`;
|
||||
this.setState(
|
||||
{
|
||||
uploadingImage: true,
|
||||
avatarImagePickerOpen: false,
|
||||
coverImagePickerOpen: false,
|
||||
coverImageUrl: isCover ? fileUrl : '', // set the path to local url first, before uploading
|
||||
thumbnailUrl: isCover ? '' : fileUrl, // same as above
|
||||
},
|
||||
() => {
|
||||
uploadImageAsset(
|
||||
`file://${evt.path}`,
|
||||
fileUrl,
|
||||
({ url }) => {
|
||||
if (isCover) {
|
||||
this.setState({ coverImageUrl: url, uploadingImage: false });
|
||||
|
@ -195,12 +206,27 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
};
|
||||
|
||||
componentDidUpdate() {
|
||||
const { channels } = this.props;
|
||||
if (channels && this.state.autoStyles.length !== channels.length) {
|
||||
const { channels = [] } = this.props;
|
||||
const { editChannelUrl } = this.state;
|
||||
if (channels.length > 0) {
|
||||
if (this.state.autoStyles.length !== channels.length) {
|
||||
this.setState({
|
||||
autoStyles: this.generateAutoStyles(channels.length),
|
||||
});
|
||||
}
|
||||
|
||||
if (editChannelUrl) {
|
||||
this.setState({ editChannelUrl: null }, () => {
|
||||
let channelToEdit = null;
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
if (editChannelUrl === channels[i].permanent_url) {
|
||||
this.prepareEdit(channels[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleCreateCancel = () => {
|
||||
|
@ -748,32 +774,13 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
style={channelCreatorStyle.coverImage}
|
||||
resizeMode={'cover'}
|
||||
source={
|
||||
coverImageUrl && coverImageUrl.trim().length > 0
|
||||
coverImageUrl !== null && coverImageUrl.trim().length > 0
|
||||
? { uri: coverImageUrl }
|
||||
: require('../../assets/default_channel_cover.png')
|
||||
}
|
||||
/>
|
||||
<View style={channelCreatorStyle.infoOverlay}>
|
||||
<Text style={channelCreatorStyle.infoText}>Tap to change</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={[channelCreatorStyle.avatarImageContainer, autoStyle]}>
|
||||
<TouchableOpacity style={channelCreatorStyle.avatarTouchArea} onPress={this.onAvatarImagePress}>
|
||||
{thumbnailUrl && (
|
||||
<Image
|
||||
style={channelCreatorStyle.avatarImage}
|
||||
resizeMode={'cover'}
|
||||
source={{ uri: thumbnailUrl }}
|
||||
/>
|
||||
)}
|
||||
{(!thumbnailUrl || thumbnailUrl.trim().length === 0) && newChannelName.length > 1 && (
|
||||
<Text style={channelIconStyle.autothumbCharacter}>
|
||||
{newChannelName.substring(0, 1).toUpperCase()}
|
||||
</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={channelCreatorStyle.editOverlay}>
|
||||
<Icon name={'edit'} style={channelCreatorStyle.editIcon} />
|
||||
</View>
|
||||
|
||||
{this.state.uploadingImage && (
|
||||
|
@ -782,6 +789,29 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
<Text style={channelCreatorStyle.uploadText}>Uploading image...</Text>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={[channelCreatorStyle.avatarImageContainer, autoStyle]}>
|
||||
<TouchableOpacity style={channelCreatorStyle.avatarTouchArea} onPress={this.onAvatarImagePress}>
|
||||
{thumbnailUrl !== null && thumbnailUrl.trim().length > 0 && (
|
||||
<Image
|
||||
style={channelCreatorStyle.avatarImage}
|
||||
resizeMode={'cover'}
|
||||
source={{ uri: thumbnailUrl }}
|
||||
/>
|
||||
)}
|
||||
{thumbnailUrl !== null && thumbnailUrl.trim().length === 0 && newChannelName.length > 1 && (
|
||||
<Text style={channelIconStyle.autothumbCharacter}>
|
||||
{newChannelName.substring(0, 1).toUpperCase()}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<View style={channelCreatorStyle.thumbnailEditOverlay}>
|
||||
<Icon name={'edit'} style={channelCreatorStyle.editIcon} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={channelCreatorStyle.card}>
|
||||
<View style={channelCreatorStyle.textInputLayout}>
|
||||
|
@ -801,18 +831,25 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
/>
|
||||
</View>
|
||||
|
||||
<View style={channelCreatorStyle.channelInputContainer}>
|
||||
<View style={channelCreatorStyle.channelInputLayout}>
|
||||
{(this.state.channelNameFocused ||
|
||||
(this.state.newChannelName != null && this.state.newChannelName.trim().length > 0)) && (
|
||||
<Text style={channelCreatorStyle.textInputTitle}>Channel name</Text>
|
||||
)}
|
||||
<View>
|
||||
<Text style={channelCreatorStyle.channelAt}>@</Text>
|
||||
|
||||
<TextInput
|
||||
editable={canSave && !creatingChannel && !updatingChannel}
|
||||
style={channelCreatorStyle.channelNameInput}
|
||||
value={this.state.newChannelName}
|
||||
onChangeText={value => this.handleNewChannelNameChange(value, true)}
|
||||
placeholder={'Channel name'}
|
||||
placeholder={this.state.channelNameFocused ? '' : 'Channel name'}
|
||||
underlineColorAndroid={Colors.NextLbryGreen}
|
||||
onFocus={() => this.setState({ channelNameFocused: true })}
|
||||
onBlur={() => this.setState({ channelNameFocused: false })}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{newChannelNameError.length > 0 && (
|
||||
<Text style={channelCreatorStyle.inlineError}>{newChannelNameError}</Text>
|
||||
)}
|
||||
|
@ -844,6 +881,7 @@ export default class ChannelCreator extends React.PureComponent {
|
|||
<TextInput
|
||||
editable={canSave && !creatingChannel && !updatingChannel}
|
||||
style={channelCreatorStyle.inputText}
|
||||
multiline
|
||||
value={this.state.description}
|
||||
onChangeText={this.handleDescriptionChange}
|
||||
placeholder={this.state.descriptionFocused ? '' : 'Description'}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
doFetchFileInfo,
|
||||
doFetchChannelListMine,
|
||||
doFetchClaimListMine,
|
||||
doFileGet,
|
||||
doPurchaseUri,
|
||||
|
@ -19,6 +20,7 @@ import {
|
|||
makeSelectThumbnailForUri,
|
||||
makeSelectTitleForUri,
|
||||
selectBalance,
|
||||
selectMyChannelClaims,
|
||||
selectMyClaimUrisWithoutChannels,
|
||||
selectPurchasedUris,
|
||||
selectFailedPurchaseUris,
|
||||
|
@ -46,6 +48,7 @@ const select = (state, props) => {
|
|||
return {
|
||||
balance: selectBalance(state),
|
||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||
channels: selectMyChannelClaims(state),
|
||||
claim: makeSelectClaimForUri(selectProps.uri)(state),
|
||||
drawerStack: selectDrawerStack(state),
|
||||
isResolvingUri: makeSelectIsUriResolving(selectProps.uri)(state),
|
||||
|
@ -75,6 +78,7 @@ const perform = dispatch => ({
|
|||
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
||||
fetchMyClaims: () => dispatch(doFetchClaimListMine()),
|
||||
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||
fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)),
|
||||
notify: data => dispatch(doToast(data)),
|
||||
popDrawerStack: () => dispatch(doPopDrawerStack()),
|
||||
|
|
|
@ -100,7 +100,7 @@ class FilePage extends React.PureComponent {
|
|||
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
|
||||
DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted);
|
||||
|
||||
const { fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
||||
const { fetchChannelListMine, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
||||
const { uri, uriVars } = navigation.state.params;
|
||||
this.setState({ uri, uriVars });
|
||||
|
||||
|
@ -108,6 +108,7 @@ class FilePage extends React.PureComponent {
|
|||
|
||||
this.fetchFileInfo(this.props);
|
||||
this.fetchCostInfo(this.props);
|
||||
fetchChannelListMine();
|
||||
|
||||
if (NativeModules.Firebase) {
|
||||
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
||||
|
@ -567,6 +568,7 @@ class FilePage extends React.PureComponent {
|
|||
const {
|
||||
balance,
|
||||
claim,
|
||||
channels,
|
||||
channelUri,
|
||||
costInfo,
|
||||
fileInfo,
|
||||
|
@ -585,6 +587,9 @@ class FilePage extends React.PureComponent {
|
|||
} = this.props;
|
||||
const { uri, autoplay } = navigation.state.params;
|
||||
|
||||
console.log(channels);
|
||||
const myChannelUris = channels ? channels.map(channel => channel.permanent_url) : [];
|
||||
const ownedClaim = myClaimUris.includes(uri) || myChannelUris.includes(uri);
|
||||
let innerContent = null;
|
||||
if ((isResolvingUri && !claim) || !claim) {
|
||||
return (
|
||||
|
@ -597,7 +602,12 @@ class FilePage extends React.PureComponent {
|
|||
)}
|
||||
{claim === null && !isResolvingUri && (
|
||||
<View style={filePageStyle.container}>
|
||||
<Text style={filePageStyle.emptyClaimText}>There's nothing at this location.</Text>
|
||||
{ownedClaim && (
|
||||
<Text style={filePageStyle.emptyClaimText}>
|
||||
It looks like you just claimed this address! Your content will appear in a few minutes.
|
||||
</Text>
|
||||
)}
|
||||
{!ownedClaim && <Text style={filePageStyle.emptyClaimText}>There's nothing at this location.</Text>}
|
||||
</View>
|
||||
)}
|
||||
<UriBar value={uri} navigation={navigation} />
|
||||
|
|
|
@ -826,6 +826,7 @@ class PublishPage extends React.PureComponent {
|
|||
)}
|
||||
<TextInput
|
||||
editable={this.state.canPublish && !this.state.publishStarted}
|
||||
multiline
|
||||
placeholder={this.state.descriptionFocused ? '' : 'Description'}
|
||||
style={publishStyle.inputText}
|
||||
value={this.state.description}
|
||||
|
|
|
@ -211,28 +211,50 @@ const channelCreatorStyle = StyleSheet.create({
|
|||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
infoOverlay: {
|
||||
editOverlay: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 24,
|
||||
position: 'absolute',
|
||||
padding: 4,
|
||||
padding: 8,
|
||||
left: 4,
|
||||
bottom: 4,
|
||||
backgroundColor: '#00000077',
|
||||
},
|
||||
infoText: {
|
||||
thumbnailEditOverlay: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 24,
|
||||
position: 'absolute',
|
||||
padding: 8,
|
||||
left: 80 / 2 - 32 / 2,
|
||||
bottom: 4,
|
||||
backgroundColor: '#00000077',
|
||||
},
|
||||
editIcon: {
|
||||
color: Colors.White,
|
||||
fontFamily: 'Inter-UI-SemiBold',
|
||||
fontSize: 12,
|
||||
},
|
||||
uploadProgress: {
|
||||
alignItems: 'center',
|
||||
borderRadius: 16,
|
||||
flexDirection: 'row',
|
||||
marginTop: 16,
|
||||
marginLeft: 16,
|
||||
marginRight: 16,
|
||||
position: 'absolute',
|
||||
top: 8,
|
||||
right: 8,
|
||||
backgroundColor: '#00000077',
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
paddingTop: 4,
|
||||
paddingBottom: 4,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
uploadText: {
|
||||
fontFamily: 'Inter-UI-Regular',
|
||||
fontSize: 14,
|
||||
marginLeft: 8,
|
||||
color: Colors.White,
|
||||
fontFamily: 'Inter-UI-SemiBold',
|
||||
fontSize: 12,
|
||||
marginLeft: 4,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -165,6 +165,9 @@ const channelPageStyle = StyleSheet.create({
|
|||
claimListContent: {
|
||||
paddingTop: 16,
|
||||
},
|
||||
actionButton: {
|
||||
backgroundColor: Colors.White,
|
||||
},
|
||||
});
|
||||
|
||||
export default channelPageStyle;
|
||||
|
|
|
@ -41,8 +41,8 @@ const filePageStyle = StyleSheet.create({
|
|||
fontFamily: 'Inter-UI-Regular',
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
marginLeft: 16,
|
||||
marginRight: 16,
|
||||
marginLeft: 24,
|
||||
marginRight: 24,
|
||||
},
|
||||
scrollContainer: {
|
||||
flex: 1,
|
||||
|
|
Loading…
Reference in a new issue