channel creator page
This commit is contained in:
parent
e74a419ffd
commit
44856e1ba1
11 changed files with 688 additions and 15 deletions
|
@ -22,7 +22,6 @@
|
||||||
"@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": "^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",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import AboutPage from 'page/about';
|
import AboutPage from 'page/about';
|
||||||
|
import ChannelCreatorPage from 'page/channelCreator';
|
||||||
import DiscoverPage from 'page/discover';
|
import DiscoverPage from 'page/discover';
|
||||||
import DownloadsPage from 'page/downloads';
|
import DownloadsPage from 'page/downloads';
|
||||||
import DrawerContent from 'component/drawerContent';
|
import DrawerContent from 'component/drawerContent';
|
||||||
|
@ -159,6 +160,12 @@ const drawer = createDrawerNavigator(
|
||||||
drawerIcon: ({ tintColor }) => <Icon name="wallet" size={drawerIconSize} style={{ color: tintColor }} />,
|
drawerIcon: ({ tintColor }) => <Icon name="wallet" size={drawerIconSize} style={{ color: tintColor }} />,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ChannelCreator: {
|
||||||
|
screen: ChannelCreatorPage,
|
||||||
|
navigationOptions: {
|
||||||
|
drawerIcon: ({ tintColor }) => <Icon name="at" size={drawerIconSize} style={{ color: tintColor }} />,
|
||||||
|
},
|
||||||
|
},
|
||||||
Publish: {
|
Publish: {
|
||||||
screen: PublishPage,
|
screen: PublishPage,
|
||||||
navigationOptions: {
|
navigationOptions: {
|
||||||
|
|
|
@ -13,7 +13,6 @@ export default class ChannelIconItem extends React.PureComponent {
|
||||||
autothumbStyle.autothumbBlue,
|
autothumbStyle.autothumbBlue,
|
||||||
autothumbStyle.autothumbLightBlue,
|
autothumbStyle.autothumbLightBlue,
|
||||||
autothumbStyle.autothumbCyan,
|
autothumbStyle.autothumbCyan,
|
||||||
autothumbStyle.autothumbTeal,
|
|
||||||
autothumbStyle.autothumbGreen,
|
autothumbStyle.autothumbGreen,
|
||||||
autothumbStyle.autothumbYellow,
|
autothumbStyle.autothumbYellow,
|
||||||
autothumbStyle.autothumbOrange,
|
autothumbStyle.autothumbOrange,
|
||||||
|
|
|
@ -12,6 +12,7 @@ const groupedMenuItems = {
|
||||||
{ icon: 'globe-americas', label: 'All content', route: Constants.DRAWER_ROUTE_TRENDING },
|
{ icon: 'globe-americas', label: 'All content', route: Constants.DRAWER_ROUTE_TRENDING },
|
||||||
],
|
],
|
||||||
'Your content': [
|
'Your content': [
|
||||||
|
{ icon: 'at', label: 'Channels', route: Constants.DRAWER_ROUTE_CHANNEL_CREATOR },
|
||||||
{ icon: 'download', label: 'Library', route: Constants.DRAWER_ROUTE_MY_LBRY },
|
{ icon: 'download', label: 'Library', route: Constants.DRAWER_ROUTE_MY_LBRY },
|
||||||
{ icon: 'cloud-upload-alt', label: 'Publishes', route: Constants.DRAWER_ROUTE_PUBLISHES },
|
{ icon: 'cloud-upload-alt', label: 'Publishes', route: Constants.DRAWER_ROUTE_PUBLISHES },
|
||||||
{ icon: 'upload', label: 'New publish', route: Constants.DRAWER_ROUTE_PUBLISH },
|
{ icon: 'upload', label: 'New publish', route: Constants.DRAWER_ROUTE_PUBLISH },
|
||||||
|
|
|
@ -25,6 +25,9 @@ const Constants = {
|
||||||
PHASE_DETAILS: 'details',
|
PHASE_DETAILS: 'details',
|
||||||
PHASE_PUBLISH: 'publish',
|
PHASE_PUBLISH: 'publish',
|
||||||
|
|
||||||
|
PHASE_LIST: 'list',
|
||||||
|
PHASE_NEW: 'create',
|
||||||
|
|
||||||
CONTENT_TAB: 'content',
|
CONTENT_TAB: 'content',
|
||||||
ABOUT_TAB: 'about',
|
ABOUT_TAB: 'about',
|
||||||
|
|
||||||
|
@ -77,6 +80,7 @@ const Constants = {
|
||||||
DRAWER_ROUTE_SEARCH: 'Search',
|
DRAWER_ROUTE_SEARCH: 'Search',
|
||||||
DRAWER_ROUTE_TRANSACTION_HISTORY: 'TransactionHistory',
|
DRAWER_ROUTE_TRANSACTION_HISTORY: 'TransactionHistory',
|
||||||
DRAWER_ROUTE_TAG: 'Tag',
|
DRAWER_ROUTE_TAG: 'Tag',
|
||||||
|
DRAWER_ROUTE_CHANNEL_CREATOR: 'ChannelCreator',
|
||||||
|
|
||||||
FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack',
|
FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack',
|
||||||
FULL_ROUTE_NAME_WALLET: 'WalletStack',
|
FULL_ROUTE_NAME_WALLET: 'WalletStack',
|
||||||
|
@ -146,4 +150,5 @@ export const DrawerRoutes = [
|
||||||
Constants.DRAWER_ROUTE_ABOUT,
|
Constants.DRAWER_ROUTE_ABOUT,
|
||||||
Constants.DRAWER_ROUTE_SEARCH,
|
Constants.DRAWER_ROUTE_SEARCH,
|
||||||
Constants.DRAWER_ROUTE_TRANSACTION_HISTORY,
|
Constants.DRAWER_ROUTE_TRANSACTION_HISTORY,
|
||||||
|
Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
|
||||||
];
|
];
|
||||||
|
|
31
src/page/channelCreator/index.js
Normal file
31
src/page/channelCreator/index.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
selectBalance,
|
||||||
|
selectMyChannelClaims,
|
||||||
|
selectFetchingMyChannels,
|
||||||
|
doFetchChannelListMine,
|
||||||
|
doCreateChannel,
|
||||||
|
doToast,
|
||||||
|
} from 'lbry-redux';
|
||||||
|
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||||
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
import ChannelCreator from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
channels: selectMyChannelClaims(state),
|
||||||
|
fetchingChannels: selectFetchingMyChannels(state),
|
||||||
|
balance: selectBalance(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
notify: data => dispatch(doToast(data)),
|
||||||
|
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
|
||||||
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
|
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_CHANNEL_CREATOR)),
|
||||||
|
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ChannelCreator);
|
473
src/page/channelCreator/view.js
Normal file
473
src/page/channelCreator/view.js
Normal file
|
@ -0,0 +1,473 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { CLAIM_VALUES, isURIValid, regexInvalidURI } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
FlatList,
|
||||||
|
Image,
|
||||||
|
NativeModules,
|
||||||
|
Picker,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import UriBar from 'component/uriBar';
|
||||||
|
import channelCreatorStyle from 'styles/channelCreator';
|
||||||
|
import channelIconStyle from 'styles/channelIcon';
|
||||||
|
|
||||||
|
export default class ChannelCreator extends React.PureComponent {
|
||||||
|
state = {
|
||||||
|
autoStyle: null,
|
||||||
|
currentSelectedValue: Constants.ITEM_ANONYMOUS,
|
||||||
|
currentPhase: Constants.PHASE_LIST,
|
||||||
|
displayName: null,
|
||||||
|
channelNameUserEdited: false,
|
||||||
|
newChannelTitle: '',
|
||||||
|
newChannelName: '',
|
||||||
|
newChannelBid: 0.1,
|
||||||
|
addingChannel: false,
|
||||||
|
creatingChannel: false,
|
||||||
|
newChannelNameError: '',
|
||||||
|
newChannelBidError: '',
|
||||||
|
createChannelError: undefined,
|
||||||
|
showCreateChannel: false,
|
||||||
|
thumbnailUrl: null,
|
||||||
|
coverImageUrl: null,
|
||||||
|
avatarImagePickerOpen: false,
|
||||||
|
coverImagePickerOpen: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
didFocusListener;
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.didFocusListener) {
|
||||||
|
this.didFocusListener.remove();
|
||||||
|
}
|
||||||
|
DeviceEventEmitter.removeListener('onDocumentPickerFilePicked', this.onFilePicked);
|
||||||
|
DeviceEventEmitter.removeListener('onDocumentPickerCanceled', this.onPickerCanceled);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.setState({
|
||||||
|
autoStyle:
|
||||||
|
ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onComponentFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
const { currentRoute } = nextProps;
|
||||||
|
const { currentRoute: prevRoute } = this.props;
|
||||||
|
|
||||||
|
if (Constants.DRAWER_ROUTE_CHANNEL_CREATOR === currentRoute && currentRoute !== prevRoute) {
|
||||||
|
this.onComponentFocused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onComponentFocused = () => {
|
||||||
|
const { channels, channelName, fetchChannelListMine, fetchingChannels } = this.props;
|
||||||
|
NativeModules.Firebase.setCurrentScreen('Channels').then(result => {
|
||||||
|
if (!channels.length && !fetchingChannels) {
|
||||||
|
fetchChannelListMine();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceEventEmitter.addListener('onDocumentPickerFilePicked', this.onFilePicked);
|
||||||
|
DeviceEventEmitter.addListener('onDocumentPickerCanceled', this.onPickerCanceled);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onFilePicked = evt => {
|
||||||
|
console.log(evt);
|
||||||
|
};
|
||||||
|
|
||||||
|
onPickerCanceled = () => {
|
||||||
|
this.setState({ avatarImagePickerOpen: false, coverImagePickerOpen: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
const { channelName } = this.props;
|
||||||
|
if (this.state.currentSelectedValue !== channelName) {
|
||||||
|
this.setState({ currentSelectedValue: channelName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCreateCancel = () => {
|
||||||
|
this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 });
|
||||||
|
};
|
||||||
|
|
||||||
|
handlePickerValueChange = (itemValue, itemIndex) => {
|
||||||
|
if (Constants.ITEM_CREATE_A_CHANNEL === itemValue) {
|
||||||
|
this.setState({ showCreateChannel: true });
|
||||||
|
} else {
|
||||||
|
this.handleCreateCancel();
|
||||||
|
this.handleChannelChange(Constants.ITEM_ANONYMOUS === itemValue ? CLAIM_VALUES.CHANNEL_ANONYMOUS : itemValue);
|
||||||
|
}
|
||||||
|
this.setState({ currentSelectedValue: itemValue });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChannelChange = value => {
|
||||||
|
const { onChannelChange } = this.props;
|
||||||
|
const { newChannelBid } = this.state;
|
||||||
|
const channel = value;
|
||||||
|
|
||||||
|
if (channel === CLAIM_VALUES.CHANNEL_NEW) {
|
||||||
|
this.setState({ addingChannel: true });
|
||||||
|
if (onChannelChange) {
|
||||||
|
onChannelChange(value);
|
||||||
|
}
|
||||||
|
this.handleNewChannelBidChange(newChannelBid);
|
||||||
|
} else {
|
||||||
|
this.setState({ addingChannel: false });
|
||||||
|
if (onChannelChange) {
|
||||||
|
onChannelChange(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleNewChannelTitleChange = value => {
|
||||||
|
this.setState({ newChannelTitle: value });
|
||||||
|
if (value && !this.state.channelNameUserEdited) {
|
||||||
|
// build the channel name based on the title
|
||||||
|
const channelName = value
|
||||||
|
.replace(new RegExp(regexInvalidURI.source, regexInvalidURI.flags + 'g'), '')
|
||||||
|
.toLowerCase();
|
||||||
|
this.handleNewChannelNameChange(channelName, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleNewChannelNameChange = (value, userInput) => {
|
||||||
|
const { notify } = this.props;
|
||||||
|
|
||||||
|
let newChannelName = value,
|
||||||
|
newChannelNameError = '';
|
||||||
|
|
||||||
|
if (newChannelName.startsWith('@')) {
|
||||||
|
newChannelName = newChannelName.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newChannelName.trim().length > 0 && !isURIValid(newChannelName)) {
|
||||||
|
newChannelNameError = 'Your channel name contains invalid characters.';
|
||||||
|
} else if (this.channelExists(newChannelName)) {
|
||||||
|
newChannelNameError = 'You have already created a channel with the same name.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput) {
|
||||||
|
this.setState({ channelNameUserEdited: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
newChannelName,
|
||||||
|
newChannelNameError,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleNewChannelBidChange = newChannelBid => {
|
||||||
|
const { balance, notify } = this.props;
|
||||||
|
let newChannelBidError;
|
||||||
|
if (newChannelBid <= 0) {
|
||||||
|
newChannelBidError = __('Please enter a deposit above 0');
|
||||||
|
} else if (newChannelBid === balance) {
|
||||||
|
newChannelBidError = __('Please decrease your deposit to account for transaction fees');
|
||||||
|
} else if (newChannelBid > balance) {
|
||||||
|
newChannelBidError = __('Deposit cannot be higher than your balance');
|
||||||
|
}
|
||||||
|
|
||||||
|
notify({ message: newChannelBidError });
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
newChannelBid,
|
||||||
|
newChannelBidError,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCreateChannelClick = () => {
|
||||||
|
const { balance, createChannel, onChannelChange, notify } = this.props;
|
||||||
|
const { newChannelBid, newChannelName } = this.state;
|
||||||
|
|
||||||
|
if (newChannelName.trim().length === 0 || !isURIValid(newChannelName.substr(1), false)) {
|
||||||
|
notify({ message: 'Your channel name contains invalid characters.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.channelExists(newChannelName)) {
|
||||||
|
notify({ message: 'You have already created a channel with the same name.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newChannelBid > balance) {
|
||||||
|
notify({ message: 'Deposit cannot be higher than your balance' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const channelName = `@${newChannelName}`;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
creatingChannel: true,
|
||||||
|
createChannelError: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const success = () => {
|
||||||
|
this.setState({
|
||||||
|
creatingChannel: false,
|
||||||
|
addingChannel: false,
|
||||||
|
currentSelectedValue: channelName,
|
||||||
|
showCreateChannel: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (onChannelChange) {
|
||||||
|
onChannelChange(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset state and go back to the channel list
|
||||||
|
this.showChannelList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const failure = () => {
|
||||||
|
notify({ message: 'Unable to create channel due to an internal error.' });
|
||||||
|
this.setState({
|
||||||
|
creatingChannel: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
createChannel(channelName, newChannelBid).then(success, failure);
|
||||||
|
};
|
||||||
|
|
||||||
|
channelExists = name => {
|
||||||
|
const { channels = [] } = this.props;
|
||||||
|
for (let channel of channels) {
|
||||||
|
if (
|
||||||
|
name.toLowerCase() === channel.name.toLowerCase() ||
|
||||||
|
`@${name}`.toLowerCase() === channel.name.toLowerCase()
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
onCoverImagePress = () => {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
avatarImagePickerOpen: false,
|
||||||
|
coverImagePickerOpen: true,
|
||||||
|
},
|
||||||
|
() => NativeModules.UtilityModule.openDocumentPicker('image/*')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onAvatarImagePress = () => {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
avatarImagePickerOpen: true,
|
||||||
|
coverImagePickerOpen: false,
|
||||||
|
},
|
||||||
|
() => NativeModules.UtilityModule.openDocumentPicker('image/*')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleNewChannelPress = () => {
|
||||||
|
this.setState({ currentPhase: Constants.PHASE_CREATE });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCreateCancel = () => {
|
||||||
|
this.showChannelList();
|
||||||
|
};
|
||||||
|
|
||||||
|
showChannelList = () => {
|
||||||
|
this.resetChannelCreator();
|
||||||
|
this.setState({ currentPhase: Constants.PHASE_LIST });
|
||||||
|
};
|
||||||
|
|
||||||
|
resetChannelCreator = () => {
|
||||||
|
this.setState({
|
||||||
|
displayName: null,
|
||||||
|
channelNameUserEdited: false,
|
||||||
|
newChannelTitle: '',
|
||||||
|
newChannelName: '',
|
||||||
|
newChannelBid: 0.1,
|
||||||
|
addingChannel: false,
|
||||||
|
creatingChannel: false,
|
||||||
|
newChannelNameError: '',
|
||||||
|
newChannelBidError: '',
|
||||||
|
createChannelError: undefined,
|
||||||
|
showCreateChannel: false,
|
||||||
|
thumbnailUrl: null,
|
||||||
|
coverImageUrl: null,
|
||||||
|
avatarImagePickerOpen: false,
|
||||||
|
coverImagePickerOpen: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const channel = this.state.addingChannel ? 'new' : this.props.channel;
|
||||||
|
const { enabled, fetchingChannels, channels = [], navigation } = this.props;
|
||||||
|
|
||||||
|
console.log(channels);
|
||||||
|
|
||||||
|
const {
|
||||||
|
autoStyle,
|
||||||
|
coverImageUrl,
|
||||||
|
currentPhase,
|
||||||
|
newChannelName,
|
||||||
|
newChannelNameError,
|
||||||
|
newChannelBid,
|
||||||
|
newChannelBidError,
|
||||||
|
creatingChannel,
|
||||||
|
createChannelError,
|
||||||
|
addingChannel,
|
||||||
|
showCreateChannel,
|
||||||
|
thumbnailUrl,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={channelCreatorStyle.container}>
|
||||||
|
<UriBar navigation={navigation} />
|
||||||
|
|
||||||
|
{currentPhase === Constants.PHASE_LIST && (
|
||||||
|
<FlatList
|
||||||
|
ListEmptyComponent={
|
||||||
|
<View style={channelCreatorStyle.listEmptyView}>
|
||||||
|
<Text style={channelCreatorStyle.listEmptyText}>
|
||||||
|
You have not created a channel. Start now by creating a new channel!
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
ListFooterComponent={
|
||||||
|
<View style={channelCreatorStyle.listFooterView}>
|
||||||
|
<Button
|
||||||
|
style={channelCreatorStyle.createChannelButton}
|
||||||
|
text={'Create a channel'}
|
||||||
|
onPress={this.handleNewChannelPress}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
style={channelCreatorStyle.scrollContainer}
|
||||||
|
contentContainerStyle={channelCreatorStyle.scrollPadding}
|
||||||
|
initialNumToRender={10}
|
||||||
|
maxToRenderPerBatch={20}
|
||||||
|
removeClippedSubviews
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<View style={channelCreatorStyle.channelListItem}>
|
||||||
|
<View style={[channelCreatorStyle.channelListAvatar, autoStyle]}>
|
||||||
|
<Text style={channelIconStyle.autothumbCharacter}>{item.name.substring(1, 2).toUpperCase()}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={channelCreatorStyle.channelListDetails}>
|
||||||
|
<Text style={channelCreatorStyle.channelListName}>{item.name}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
data={channels}
|
||||||
|
keyExtractor={(item, index) => item.claim_id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentPhase === Constants.PHASE_CREATE && (
|
||||||
|
<View style={channelCreatorStyle.createChannelContainer}>
|
||||||
|
<View style={channelCreatorStyle.imageSelectors}>
|
||||||
|
<TouchableOpacity style={channelCreatorStyle.coverImageTouchArea} onPress={this.onCoverImagePress}>
|
||||||
|
<Image
|
||||||
|
style={channelCreatorStyle.coverImage}
|
||||||
|
resizeMode={'cover'}
|
||||||
|
source={
|
||||||
|
coverImageUrl && coverImageUrl.trim().length > 0
|
||||||
|
? { uri: coverImageUrl }
|
||||||
|
: require('../../assets/default_channel_cover.png')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<View style={channelCreatorStyle.card}>
|
||||||
|
<TextInput
|
||||||
|
style={channelCreatorStyle.channelTitleInput}
|
||||||
|
value={this.state.newChannelTitle}
|
||||||
|
onChangeText={this.handleNewChannelTitleChange}
|
||||||
|
placeholder={'Title'}
|
||||||
|
underlineColorAndroid={Colors.NextLbryGreen}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={channelCreatorStyle.channelInputContainer}>
|
||||||
|
<Text style={channelCreatorStyle.channelAt}>@</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
style={channelCreatorStyle.channelNameInput}
|
||||||
|
value={this.state.newChannelName}
|
||||||
|
onChangeText={value => this.handleNewChannelNameChange(value, true)}
|
||||||
|
placeholder={'Channel name'}
|
||||||
|
underlineColorAndroid={Colors.NextLbryGreen}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{newChannelNameError.length > 0 && (
|
||||||
|
<Text style={channelCreatorStyle.inlineError}>{newChannelNameError}</Text>
|
||||||
|
)}
|
||||||
|
<View style={channelCreatorStyle.bidRow}>
|
||||||
|
<Text style={channelCreatorStyle.label}>Deposit</Text>
|
||||||
|
<TextInput
|
||||||
|
style={channelCreatorStyle.bidAmountInput}
|
||||||
|
value={String(newChannelBid)}
|
||||||
|
onChangeText={this.handleNewChannelBidChange}
|
||||||
|
placeholder={'0.00'}
|
||||||
|
keyboardType={'number-pad'}
|
||||||
|
underlineColorAndroid={Colors.NextLbryGreen}
|
||||||
|
/>
|
||||||
|
<Text style={channelCreatorStyle.currency}>LBC</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={channelCreatorStyle.helpText}>
|
||||||
|
This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={channelCreatorStyle.buttonContainer}>
|
||||||
|
{creatingChannel && <ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />}
|
||||||
|
{!creatingChannel && (
|
||||||
|
<View style={channelCreatorStyle.buttons}>
|
||||||
|
<Link style={channelCreatorStyle.cancelLink} text="Cancel" onPress={this.handleCreateCancel} />
|
||||||
|
<Button
|
||||||
|
style={channelCreatorStyle.createButton}
|
||||||
|
disabled={!(newChannelName.trim().length > 0 && newChannelBid > 0)}
|
||||||
|
text="Create"
|
||||||
|
onPress={this.handleCreateChannelClick}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FloatingWalletBalance navigation={navigation} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
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';
|
||||||
|
@ -512,18 +511,7 @@ class PublishPage extends React.PureComponent {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleUploadPressed = () => {
|
handleUploadPressed = () => {};
|
||||||
DocumentPicker.pick({ type: [DocumentPicker.types.allFiles] })
|
|
||||||
.then(file => {
|
|
||||||
// console.log(file);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (!DocumentPicker.isCancel(error)) {
|
|
||||||
// notify the user
|
|
||||||
// console.log(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getRandomFileId = () => {
|
getRandomFileId = () => {
|
||||||
// generate a random id for a photo or recorded video between 1 and 20 (for creating thumbnails)
|
// generate a random id for a photo or recorded video between 1 and 20 (for creating thumbnails)
|
||||||
|
|
|
@ -33,6 +33,15 @@ class PublishesPage extends React.PureComponent {
|
||||||
this.onComponentFocused();
|
this.onComponentFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
const { currentRoute } = nextProps;
|
||||||
|
const { currentRoute: prevRoute } = this.props;
|
||||||
|
|
||||||
|
if (Constants.DRAWER_ROUTE_PUBLISHES === currentRoute && currentRoute !== prevRoute) {
|
||||||
|
this.onComponentFocused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onComponentFocused = () => {
|
onComponentFocused = () => {
|
||||||
const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props;
|
const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props;
|
||||||
pushDrawerStack();
|
pushDrawerStack();
|
||||||
|
|
157
src/styles/channelCreator.js
Normal file
157
src/styles/channelCreator.js
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import { Dimensions, StyleSheet } from 'react-native';
|
||||||
|
import Colors from './colors';
|
||||||
|
|
||||||
|
const screenDimension = Dimensions.get('window');
|
||||||
|
const screenWidth = screenDimension.width;
|
||||||
|
|
||||||
|
const channelCreatorStyle = StyleSheet.create({
|
||||||
|
card: {
|
||||||
|
backgroundColor: Colors.White,
|
||||||
|
marginTop: 16,
|
||||||
|
marginLeft: 16,
|
||||||
|
marginRight: 16,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: Colors.PageBackground,
|
||||||
|
},
|
||||||
|
channelPicker: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
height: 52,
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
bidRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
channelNameInput: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
paddingLeft: 20,
|
||||||
|
},
|
||||||
|
bidAmountInput: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
marginLeft: 16,
|
||||||
|
textAlign: 'right',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
helpText: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
channelTitleInput: {
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
createChannelContainer: {
|
||||||
|
marginTop: 60,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
channelAt: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 4,
|
||||||
|
top: 13,
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
marginLeft: 16,
|
||||||
|
marginRight: 16,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
cancelLink: {
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
createButton: {
|
||||||
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
},
|
||||||
|
inlineError: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.Red,
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
imageSelectors: {
|
||||||
|
width: '100%',
|
||||||
|
height: 160,
|
||||||
|
},
|
||||||
|
coverImageTouchArea: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
coverImage: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
avatarImageContainer: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: screenWidth / 2 - 80 / 2,
|
||||||
|
bottom: -16,
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
borderRadius: 160,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
avatarTouchArea: {
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
avatarImage: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
listFooterView: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
createChannelButton: {
|
||||||
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
},
|
||||||
|
scrollContainer: {
|
||||||
|
marginTop: 60,
|
||||||
|
marginLeft: 16,
|
||||||
|
marginRight: 16,
|
||||||
|
},
|
||||||
|
scrollPadding: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
|
channelListItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
marginBottom: 16,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
channelListName: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
channelListAvatar: {
|
||||||
|
marginRight: 16,
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
borderRadius: 160,
|
||||||
|
overflow: 'hidden',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default channelCreatorStyle;
|
|
@ -156,6 +156,10 @@ const publishStyle = StyleSheet.create({
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
},
|
},
|
||||||
|
listEmptyText: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
titleRow: {
|
titleRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
|
Loading…
Reference in a new issue