Sync user settings #45
21 changed files with 318 additions and 117 deletions
BIN
src/assets/gerbil-happy.png
Normal file
BIN
src/assets/gerbil-happy.png
Normal file
Binary file not shown.
Before Width: | Height: | Size: 265 KiB After Width: | Height: | Size: 265 KiB |
BIN
src/assets/gerbil-sad.png
Normal file
BIN
src/assets/gerbil-sad.png
Normal file
Binary file not shown.
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
|
@ -29,8 +29,9 @@ import {
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { AppState, BackHandler, Linking, NativeModules, TextInput, ToastAndroid } from 'react-native';
|
import { AppState, BackHandler, Linking, NativeModules, TextInput, ToastAndroid } from 'react-native';
|
||||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
import { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux';
|
import { SETTINGS, doDismissToast, doPopulateSharedUserState, doToast, selectToast } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
|
Lbryio,
|
||||||
doGetSync,
|
doGetSync,
|
||||||
doUserCheckEmailVerified,
|
doUserCheckEmailVerified,
|
||||||
doUserEmailVerify,
|
doUserEmailVerify,
|
||||||
|
@ -305,6 +306,13 @@ class AppWithNavigationState extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getUserSettings = () => {
|
||||||
|
const { dispatch } = this.props;
|
||||||
|
Lbryio.call('user_settings', 'get').then(settings => {
|
||||||
|
dispatch(doPopulateSharedUserState(settings));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||||
BackHandler.removeEventListener('hardwareBackPress');
|
BackHandler.removeEventListener('hardwareBackPress');
|
||||||
|
@ -321,12 +329,8 @@ class AppWithNavigationState extends React.Component {
|
||||||
NativeModules.Firebase.track('email_verified', { email: user.primary_email });
|
NativeModules.Firebase.track('email_verified', { email: user.primary_email });
|
||||||
ToastAndroid.show('Your email address was successfully verified.', ToastAndroid.LONG);
|
ToastAndroid.show('Your email address was successfully verified.', ToastAndroid.LONG);
|
||||||
|
|
||||||
// upon successful email verification, do wallet sync (if password has been set)
|
// get user settings after email verification
|
||||||
NativeModules.UtilityModule.getSecureValue(Constants.KEY_FIRST_RUN_PASSWORD).then(walletPassword => {
|
this.getUserSettings();
|
||||||
if (walletPassword && walletPassword.trim().length > 0) {
|
|
||||||
dispatch(doGetSync(walletPassword));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default class ChannelSelector extends React.PureComponent {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { channels = [], channelName, fetchChannelListMine, fetchingChannels } = this.props;
|
const { channels = [], channelName, fetchChannelListMine, fetchingChannels } = this.props;
|
||||||
if (!channels.length && !fetchingChannels) {
|
if ((!channels || channels.length === 0) && !fetchingChannels) {
|
||||||
fetchChannelListMine();
|
fetchChannelListMine();
|
||||||
}
|
}
|
||||||
this.setState({ currentSelectedValue: channelName });
|
this.setState({ currentSelectedValue: channelName });
|
||||||
|
@ -37,7 +37,7 @@ export default class ChannelSelector extends React.PureComponent {
|
||||||
const { channels: prevChannels = [], channelName } = this.props;
|
const { channels: prevChannels = [], channelName } = this.props;
|
||||||
const { channels = [] } = nextProps;
|
const { channels = [] } = nextProps;
|
||||||
|
|
||||||
if (channels.length !== prevChannels.length && channelName !== this.state.currentSelectedValue) {
|
if (channels && channels.length !== prevChannels.length && channelName !== this.state.currentSelectedValue) {
|
||||||
this.setState({ currentSelectedValue: channelName });
|
this.setState({ currentSelectedValue: channelName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,9 @@ 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 { enabled, 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 ? channels.map(ch => ch.name) : []
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
newChannelName,
|
newChannelName,
|
||||||
|
|
4
src/component/emptyStateView/index.js
Normal file
4
src/component/emptyStateView/index.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import EmptyStateView from './view';
|
||||||
|
|
||||||
|
export default connect()(EmptyStateView);
|
26
src/component/emptyStateView/view.js
Normal file
26
src/component/emptyStateView/view.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { NativeModules, Text, View, Image, TouchableOpacity } from 'react-native';
|
||||||
|
import Button from '../button';
|
||||||
|
import emptyStateStyle from 'styles/emptyState';
|
||||||
|
|
||||||
|
class EmptyStateView extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
const { message, buttonText, inner, onButtonPress } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[emptyStateStyle.container, inner ? emptyStateStyle.innerContainer : emptyStateStyle.outerContainer]}
|
||||||
|
>
|
||||||
|
<Image style={emptyStateStyle.image} resizeMode={'stretch'} source={require('../../assets/gerbil-happy.png')} />
|
||||||
|
<Text style={emptyStateStyle.message}>{message}</Text>
|
||||||
|
{buttonText && (
|
||||||
|
<View style={emptyStateStyle.buttonContainer}>
|
||||||
|
<Button style={emptyStateStyle.button} text={buttonText} onPress={onButtonPress} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmptyStateView;
|
|
@ -59,7 +59,8 @@ class RewardCard extends React.PureComponent<Props> {
|
||||||
getDisplayAmount = () => {
|
getDisplayAmount = () => {
|
||||||
const { reward } = this.props;
|
const { reward } = this.props;
|
||||||
if (reward) {
|
if (reward) {
|
||||||
if (reward.reward_range && reward.reward_range.includes('-')) {
|
const claimed = !!reward.transaction_id;
|
||||||
|
if (!claimed && reward.reward_range && reward.reward_range.includes('-')) {
|
||||||
return reward.reward_range.split('-')[0] + '+'; // ex: 5+
|
return reward.reward_range.split('-')[0] + '+'; // ex: 5+
|
||||||
} else if (reward.reward_amount > 0) {
|
} else if (reward.reward_amount > 0) {
|
||||||
return reward.reward_amount;
|
return reward.reward_amount;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
|
import { doAbandonClaim, doFetchChannelListMine, makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
|
||||||
import { doPopDrawerStack } from 'redux/actions/drawer';
|
import { doPopDrawerStack } from 'redux/actions/drawer';
|
||||||
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
|
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
|
||||||
import { selectDrawerStack } from 'redux/selectors/drawer';
|
import { selectDrawerStack } from 'redux/selectors/drawer';
|
||||||
|
@ -15,6 +15,8 @@ const select = (state, props) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)),
|
||||||
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
popDrawerStack: () => dispatch(doPopDrawerStack()),
|
popDrawerStack: () => dispatch(doPopDrawerStack()),
|
||||||
setSortByItem: item => dispatch(doSetSortByItem(item)),
|
setSortByItem: item => dispatch(doSetSortByItem(item)),
|
||||||
setTimeItem: item => dispatch(doSetTimeItem(item)),
|
setTimeItem: item => dispatch(doSetTimeItem(item)),
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ClaimList from 'component/claimList';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
import ModalPicker from 'component/modalPicker';
|
import ModalPicker from 'component/modalPicker';
|
||||||
|
@ -47,7 +48,9 @@ class ChannelPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const { fetchChannelListMine } = this.props;
|
||||||
NativeModules.Firebase.setCurrentScreen('Channel');
|
NativeModules.Firebase.setCurrentScreen('Channel');
|
||||||
|
fetchChannelListMine();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortByItemSelected = item => {
|
handleSortByItemSelected = item => {
|
||||||
|
@ -128,9 +131,7 @@ class ChannelPage extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<View style={channelPageStyle.aboutTab}>
|
<View style={channelPageStyle.aboutTab}>
|
||||||
{!websiteUrl && !email && !description && (
|
{!websiteUrl && !email && !description && (
|
||||||
<View style={channelPageStyle.busyContainer}>
|
<EmptyStateView message={"There's nothing here yet.\nPlease check back later."} />
|
||||||
<Text style={channelPageStyle.infoText}>Nothing here yet. Please check back later.</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(websiteUrl || email || description) && (
|
{(websiteUrl || email || description) && (
|
||||||
|
@ -266,7 +267,7 @@ class ChannelPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
{ownedChannel && (
|
{ownedChannel && (
|
||||||
<Button
|
<Button
|
||||||
style={channelPageStyle.deleteButton}
|
style={[channelPageStyle.actionButton, channelPageStyle.deleteButton]}
|
||||||
theme={'light'}
|
theme={'light'}
|
||||||
icon={'trash-alt'}
|
icon={'trash-alt'}
|
||||||
text={'Delete'}
|
text={'Delete'}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Button from 'component/button';
|
||||||
import ChannelIconItem from 'component/channelIconItem';
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
|
@ -175,10 +176,8 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
|
|
||||||
if (!isEditMode && hasFormState) {
|
if (!isEditMode && hasFormState) {
|
||||||
this.loadPendingFormState();
|
this.loadPendingFormState();
|
||||||
this.setState({ currentPhase: Constants.PHASE_CREATE });
|
|
||||||
} else {
|
|
||||||
this.setState({ currentPhase: Constants.PHASE_LIST });
|
|
||||||
}
|
}
|
||||||
|
this.setState({ currentPhase: isEditMode || hasFormState ? Constants.PHASE_CREATE : Constants.PHASE_LIST });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,7 +239,7 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { channels = [] } = this.props;
|
const { channels = [] } = this.props;
|
||||||
const { editChannelUrl } = this.state;
|
const { editChannelUrl } = this.state;
|
||||||
if (channels.length > 0) {
|
if (channels && channels.length > 0) {
|
||||||
if (this.state.autoStyles.length !== channels.length) {
|
if (this.state.autoStyles.length !== channels.length) {
|
||||||
this.setState({
|
this.setState({
|
||||||
autoStyles: this.generateAutoStyles(channels.length),
|
autoStyles: this.generateAutoStyles(channels.length),
|
||||||
|
@ -534,10 +533,12 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
showChannelList = () => {
|
showChannelList = () => {
|
||||||
const { popDrawerStack } = this.props;
|
const { drawerStack, popDrawerStack } = this.props;
|
||||||
popDrawerStack();
|
if (drawerStack[drawerStack.length - 1].route === Constants.DRAWER_ROUTE_CHANNEL_CREATOR_FORM) {
|
||||||
this.resetChannelCreator();
|
popDrawerStack();
|
||||||
|
}
|
||||||
this.setState({ currentPhase: Constants.PHASE_LIST });
|
this.setState({ currentPhase: Constants.PHASE_LIST });
|
||||||
|
this.resetChannelCreator();
|
||||||
};
|
};
|
||||||
|
|
||||||
resetChannelCreator = () => {
|
resetChannelCreator = () => {
|
||||||
|
@ -606,6 +607,7 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
this.setState({
|
this.setState({
|
||||||
claimId: channel.claim_id,
|
claimId: channel.claim_id,
|
||||||
currentPhase: Constants.PHASE_CREATE,
|
currentPhase: Constants.PHASE_CREATE,
|
||||||
|
displayName: value && value.title ? value.title : channel.name.substring(1),
|
||||||
editMode: true,
|
editMode: true,
|
||||||
coverImageUrl: value && value.cover ? value.cover.url : null,
|
coverImageUrl: value && value.cover ? value.cover.url : null,
|
||||||
currentChannelName: channel.name.substring(1),
|
currentChannelName: channel.name.substring(1),
|
||||||
|
@ -744,6 +746,8 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
uploadingImage,
|
uploadingImage,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
|
const hasChannels = channels && channels.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={channelCreatorStyle.container}>
|
<View style={channelCreatorStyle.container}>
|
||||||
<UriBar
|
<UriBar
|
||||||
|
@ -756,34 +760,34 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
onExitSelectionMode={this.onExitSelectionMode}
|
onExitSelectionMode={this.onExitSelectionMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{fetchingChannels && (
|
||||||
|
<View style={channelCreatorStyle.loading}>
|
||||||
|
<ActivityIndicator size={'large'} color={Colors.NextLbryGreen} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentPhase === Constants.PHASE_LIST && !fetchingChannels && !hasChannels && (
|
||||||
|
<EmptyStateView
|
||||||
|
message={'You have not created a channel.\nStart now by creating a new channel!'}
|
||||||
|
buttonText={'Create a channel'}
|
||||||
|
onButtonPress={this.handleNewChannelPress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{currentPhase === Constants.PHASE_LIST && (
|
{currentPhase === Constants.PHASE_LIST && (
|
||||||
<FlatList
|
<FlatList
|
||||||
extraData={this.state}
|
extraData={this.state}
|
||||||
ListHeaderComponent={
|
ListFooterComponent={
|
||||||
fetchingChannels ? (
|
!channels || channels.length === 0 ? null : (
|
||||||
<View style={channelCreatorStyle.listHeader}>
|
<View style={channelCreatorStyle.listFooter}>
|
||||||
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
<Button
|
||||||
</View>
|
style={channelCreatorStyle.createChannelButton}
|
||||||
) : null
|
text={'Create a channel'}
|
||||||
}
|
onPress={this.handleNewChannelPress}
|
||||||
ListEmptyComponent={
|
/>
|
||||||
fetchingChannels ? null : (
|
|
||||||
<View style={channelCreatorStyle.listEmpty}>
|
|
||||||
<Text style={channelCreatorStyle.listEmptyText}>
|
|
||||||
You have not created a channel. Start now by creating a new channel!
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ListFooterComponent={
|
|
||||||
<View style={channelCreatorStyle.listFooter}>
|
|
||||||
<Button
|
|
||||||
style={channelCreatorStyle.createChannelButton}
|
|
||||||
text={'Create a channel'}
|
|
||||||
onPress={this.handleNewChannelPress}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
style={channelCreatorStyle.scrollContainer}
|
style={channelCreatorStyle.scrollContainer}
|
||||||
contentContainerStyle={channelCreatorStyle.scrollPadding}
|
contentContainerStyle={channelCreatorStyle.scrollPadding}
|
||||||
initialNumToRender={10}
|
initialNumToRender={10}
|
||||||
|
@ -825,7 +829,7 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
data={channels.filter(channel => !abandoningClaimIds.includes(channel.claim_id))}
|
data={channels ? channels.filter(channel => !abandoningClaimIds.includes(channel.claim_id)) : []}
|
||||||
keyExtractor={(item, index) => item.claim_id}
|
keyExtractor={(item, index) => item.claim_id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -864,7 +868,7 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
source={{ uri: thumbnailUrl }}
|
source={{ uri: thumbnailUrl }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{thumbnailUrl !== null && thumbnailUrl.trim().length === 0 && newChannelName.length > 1 && (
|
{(thumbnailUrl === null || thumbnailUrl.trim().length === 0) && newChannelName.length > 1 && (
|
||||||
<Text style={channelIconStyle.autothumbCharacter}>
|
<Text style={channelIconStyle.autothumbCharacter}>
|
||||||
{newChannelName.substring(0, 1).toUpperCase()}
|
{newChannelName.substring(0, 1).toUpperCase()}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { __, navigateToUri, uriFromFileInfo } from 'utils/helper';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import PageHeader from 'component/pageHeader';
|
import PageHeader from 'component/pageHeader';
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import FileListItem from 'component/fileListItem';
|
import FileListItem from 'component/fileListItem';
|
||||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
import StorageStatsCard from 'component/storageStatsCard';
|
import StorageStatsCard from 'component/storageStatsCard';
|
||||||
|
@ -154,6 +155,10 @@ class DownloadsPage extends React.PureComponent {
|
||||||
onDeleteActionPressed={this.onDeleteActionPressed}
|
onDeleteActionPressed={this.onDeleteActionPressed}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{!fetching && !hasDownloads && (
|
||||||
|
<EmptyStateView message={'You do not have any\ndownloaded content on this device.'} />
|
||||||
|
)}
|
||||||
|
|
||||||
<View style={downloadsStyle.subContainer}>
|
<View style={downloadsStyle.subContainer}>
|
||||||
{hasDownloads && <StorageStatsCard fileInfos={this.getFilteredFileInfos()} />}
|
{hasDownloads && <StorageStatsCard fileInfos={this.getFilteredFileInfos()} />}
|
||||||
{fetching && (
|
{fetching && (
|
||||||
|
@ -161,11 +166,7 @@ class DownloadsPage extends React.PureComponent {
|
||||||
<ActivityIndicator size="large" color={Colors.NextLbryGreen} style={downloadsStyle.loading} />
|
<ActivityIndicator size="large" color={Colors.NextLbryGreen} style={downloadsStyle.loading} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{!fetching && !hasDownloads && (
|
|
||||||
<View style={downloadsStyle.busyContainer}>
|
|
||||||
<Text style={downloadsStyle.noDownloadsText}>You do not have any downloaded content on this device.</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
{!fetching && hasDownloads && (
|
{!fetching && hasDownloads && (
|
||||||
<FlatList
|
<FlatList
|
||||||
extraData={this.state}
|
extraData={this.state}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { navigateBack, navigateToUri } from 'utils/helper';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import ImageViewer from 'react-native-image-zoom-viewer';
|
import ImageViewer from 'react-native-image-zoom-viewer';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import Tag from 'component/tag';
|
import Tag from 'component/tag';
|
||||||
import ChannelPage from 'page/channel';
|
import ChannelPage from 'page/channel';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
|
@ -100,7 +101,7 @@ class FilePage extends React.PureComponent {
|
||||||
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
|
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
|
||||||
DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted);
|
DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted);
|
||||||
|
|
||||||
const { fetchChannelListMine, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
const { fetchMyClaims, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
|
||||||
const { uri, uriVars } = navigation.state.params;
|
const { uri, uriVars } = navigation.state.params;
|
||||||
this.setState({ uri, uriVars });
|
this.setState({ uri, uriVars });
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
this.fetchFileInfo(this.props);
|
this.fetchFileInfo(this.props);
|
||||||
this.fetchCostInfo(this.props);
|
this.fetchCostInfo(this.props);
|
||||||
fetchChannelListMine();
|
fetchMyClaims();
|
||||||
|
|
||||||
if (NativeModules.Firebase) {
|
if (NativeModules.Firebase) {
|
||||||
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
NativeModules.Firebase.track('open_file_page', { uri: uri });
|
||||||
|
@ -590,14 +591,15 @@ class FilePage extends React.PureComponent {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { uri, autoplay } = navigation.state.params;
|
const { uri, autoplay } = navigation.state.params;
|
||||||
|
|
||||||
|
const { isChannel } = parseURI(uri);
|
||||||
const myChannelUris = channels ? channels.map(channel => channel.permanent_url) : [];
|
const myChannelUris = channels ? channels.map(channel => channel.permanent_url) : [];
|
||||||
const ownedClaim = myClaimUris.includes(uri) || myChannelUris.includes(uri);
|
const ownedClaim = myClaimUris.includes(uri) || myChannelUris.includes(uri);
|
||||||
const { isChannel } = parseURI(uri);
|
|
||||||
|
|
||||||
let innerContent = null;
|
let innerContent = null;
|
||||||
if ((isResolvingUri && !claim) || !claim) {
|
if ((isResolvingUri && !claim) || !claim) {
|
||||||
return (
|
return (
|
||||||
<View style={filePageStyle.container}>
|
<View style={filePageStyle.container}>
|
||||||
|
<UriBar value={uri} navigation={navigation} />
|
||||||
{isResolvingUri && (
|
{isResolvingUri && (
|
||||||
<View style={filePageStyle.busyContainer}>
|
<View style={filePageStyle.busyContainer}>
|
||||||
<ActivityIndicator size="large" color={Colors.NextLbryGreen} />
|
<ActivityIndicator size="large" color={Colors.NextLbryGreen} />
|
||||||
|
@ -607,16 +609,29 @@ class FilePage extends React.PureComponent {
|
||||||
{claim === null && !isResolvingUri && (
|
{claim === null && !isResolvingUri && (
|
||||||
<View style={filePageStyle.container}>
|
<View style={filePageStyle.container}>
|
||||||
{ownedClaim && (
|
{ownedClaim && (
|
||||||
<Text style={filePageStyle.emptyClaimText}>
|
<EmptyStateView
|
||||||
{isChannel
|
message={
|
||||||
? 'It looks like you just created this channel. It will appear in a few minutes.'
|
isChannel
|
||||||
: 'It looks you just published this content. It will appear in a few minutes.'}
|
? 'It looks like you just created this channel. It will appear in a few minutes.'
|
||||||
</Text>
|
: 'It looks you just published this content. It will appear in a few minutes.'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!ownedClaim && (
|
||||||
|
<EmptyStateView
|
||||||
|
message={"There's nothing at this location."}
|
||||||
|
buttonText={'Publish something here'}
|
||||||
|
onButtonPress={() =>
|
||||||
|
navigation.navigate({
|
||||||
|
routeName: Constants.DRAWER_ROUTE_PUBLISH,
|
||||||
|
params: { vanityUrl: uri.trim() },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!ownedClaim && <Text style={filePageStyle.emptyClaimText}>There's nothing at this location.</Text>}
|
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<UriBar value={uri} navigation={navigation} />
|
<FloatingWalletBalance navigation={navigation} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
doToast,
|
doToast,
|
||||||
doUpdatePublishForm,
|
doUpdatePublishForm,
|
||||||
doUploadThumbnail,
|
|
||||||
selectBalance,
|
selectBalance,
|
||||||
selectPublishFormValues,
|
selectPublishFormValues,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
|
@ -28,7 +27,6 @@ const perform = dispatch => ({
|
||||||
clearPublishFormState: () => dispatch(doClearPublishFormState()),
|
clearPublishFormState: () => dispatch(doClearPublishFormState()),
|
||||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||||
updatePublishFormState: data => dispatch(doUpdatePublishFormState(data)),
|
updatePublishFormState: data => dispatch(doUpdatePublishFormState(data)),
|
||||||
uploadThumbnail: (filePath, fsAdapter) => dispatch(doUploadThumbnail(filePath, null, fsAdapter)),
|
|
||||||
publish: (success, fail) => dispatch(doPublish(success, fail)),
|
publish: (success, fail) => dispatch(doPublish(success, fail)),
|
||||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
|
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
|
||||||
|
|
|
@ -43,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 { __, navigateToUri } from 'utils/helper';
|
import { __, navigateToUri, uploadImageAsset } from 'utils/helper';
|
||||||
|
|
||||||
const languages = {
|
const languages = {
|
||||||
en: 'English',
|
en: 'English',
|
||||||
|
@ -129,6 +129,8 @@ class PublishPage extends React.PureComponent {
|
||||||
uploadedThumbnailUri: null,
|
uploadedThumbnailUri: null,
|
||||||
vanityUrlSet: false,
|
vanityUrlSet: false,
|
||||||
|
|
||||||
|
thumbnailImagePickerOpen: false,
|
||||||
|
|
||||||
// other
|
// other
|
||||||
publishStarted: false,
|
publishStarted: false,
|
||||||
};
|
};
|
||||||
|
@ -218,10 +220,8 @@ class PublishPage extends React.PureComponent {
|
||||||
// replace name with the specified vanity URL if there was one in the pending state
|
// replace name with the specified vanity URL if there was one in the pending state
|
||||||
this.setState({ name: this.state.vanityUrl });
|
this.setState({ name: this.state.vanityUrl });
|
||||||
}
|
}
|
||||||
this.setState({ currentPhase: Constants.PHASE_DETAILS });
|
|
||||||
} else {
|
|
||||||
this.setState({ currentPhase: Constants.PHASE_SELECTOR });
|
|
||||||
}
|
}
|
||||||
|
this.setState({ currentPhase: isEditMode || hasFormState ? Constants.PHASE_DETAILS : Constants.PHASE_SELECTOR });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,6 +256,7 @@ class PublishPage extends React.PureComponent {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
editMode: true,
|
editMode: true,
|
||||||
|
publishStarted: false,
|
||||||
currentPhase: Constants.PHASE_DETAILS,
|
currentPhase: Constants.PHASE_DETAILS,
|
||||||
|
|
||||||
hasEditedContentAddress: true,
|
hasEditedContentAddress: true,
|
||||||
|
@ -382,10 +383,12 @@ class PublishPage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePublishSuccess = data => {
|
handlePublishSuccess = data => {
|
||||||
const { navigation, notify } = this.props;
|
const { clearPublishFormState, navigation, notify } = this.props;
|
||||||
notify({
|
notify({
|
||||||
message: `Your content was successfully published to ${this.state.uri}. It will be available in a few mintues.`,
|
message: `Your content was successfully published to ${this.state.uri}. It will be available in a few mintues.`,
|
||||||
});
|
});
|
||||||
|
clearPublishFormState();
|
||||||
|
this.setState({ publishStarted: false });
|
||||||
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISHES, params: { publishSuccess: true } });
|
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISHES, params: { publishSuccess: true } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -436,6 +439,7 @@ class PublishPage extends React.PureComponent {
|
||||||
updatePublishFormState({ currentMedia: media, name: newName });
|
updatePublishFormState({ currentMedia: media, name: newName });
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
|
publishStarted: false,
|
||||||
currentMedia: media,
|
currentMedia: media,
|
||||||
title: null, // no title autogeneration (user will fill this in)
|
title: null, // no title autogeneration (user will fill this in)
|
||||||
name: newName,
|
name: newName,
|
||||||
|
@ -453,7 +457,7 @@ class PublishPage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
showSelector() {
|
showSelector() {
|
||||||
const { updatePublishForm } = this.props;
|
const { clearPublishFormState, updatePublishForm } = this.props;
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
|
@ -490,9 +494,12 @@ class PublishPage extends React.PureComponent {
|
||||||
selectedChannel: null,
|
selectedChannel: null,
|
||||||
uploadedThumbnailUri: null,
|
uploadedThumbnailUri: null,
|
||||||
|
|
||||||
|
thumbnailImagePickerOpen: false,
|
||||||
|
|
||||||
vanityUrlSet: false,
|
vanityUrlSet: false,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
clearPublishFormState();
|
||||||
// reset thumbnail
|
// reset thumbnail
|
||||||
updatePublishForm({ thumbnail: null });
|
updatePublishForm({ thumbnail: null });
|
||||||
}
|
}
|
||||||
|
@ -526,19 +533,59 @@ class PublishPage extends React.PureComponent {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
onFilePicked = evt => {
|
handleThumbnailUploadSuccess = ({ url }) => {
|
||||||
this.setState({ documentPickerOpen: false }, () => {
|
const { updatePublishFormState } = this.props;
|
||||||
const currentMedia = {
|
|
||||||
id: -1,
|
this.setState({
|
||||||
filePath: `file://${evt.path}`,
|
uploadThumbnailStarted: false,
|
||||||
duration: 0,
|
currentThumbnailUri: url,
|
||||||
};
|
uploadedThumbnailUri: url,
|
||||||
this.setCurrentMedia(currentMedia);
|
|
||||||
});
|
});
|
||||||
|
updatePublishFormState({ currentThumbnailUri: url, uploadedThumbnailUri: url });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleThumbnailUploadFailure = err => {
|
||||||
|
const { notify } = this.props;
|
||||||
|
this.setState({ uploadThumbnailStarted: false });
|
||||||
|
notify({ message: 'The thumbnail could not be uploaded. Please try again.' });
|
||||||
|
};
|
||||||
|
|
||||||
|
onFilePicked = evt => {
|
||||||
|
const { notify } = this.props;
|
||||||
|
if (evt.path && evt.path.length > 0) {
|
||||||
|
const fileUrl = `file://${evt.path}`;
|
||||||
|
|
||||||
|
if (this.state.documentPickerOpen) {
|
||||||
|
this.setState({ documentPickerOpen: false, thumbnailImagePickerOpen: false }, () => {
|
||||||
|
const currentMedia = {
|
||||||
|
id: -1,
|
||||||
|
filePath: fileUrl,
|
||||||
|
duration: 0,
|
||||||
|
};
|
||||||
|
this.setCurrentMedia(currentMedia);
|
||||||
|
});
|
||||||
|
} else if (this.state.thumbnailImagePickerOpen) {
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
documentPickerOpen: false,
|
||||||
|
thumbnailImagePickerOpen: false,
|
||||||
|
uploadThumbnailStarted: true,
|
||||||
|
currentThumbnailUri: fileUrl,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// upload a new thumbnail
|
||||||
|
uploadImageAsset(fileUrl, this.handleThumbnailUploadSuccess, this.handleThumbnailUploadFailure);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// could not determine the file path
|
||||||
|
notify({ message: 'The path could not be determined. Please try a different file.' });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onPickerCanceled = () => {
|
onPickerCanceled = () => {
|
||||||
this.setState({ documentPickerOpen: false });
|
this.setState({ documentPickerOpen: false, thumbnailImagePickerOpen: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCloseCameraPressed = () => {
|
handleCloseCameraPressed = () => {
|
||||||
|
@ -573,6 +620,7 @@ class PublishPage extends React.PureComponent {
|
||||||
{
|
{
|
||||||
currentThumbnailUri: null,
|
currentThumbnailUri: null,
|
||||||
updatingThumbnailUri: false,
|
updatingThumbnailUri: false,
|
||||||
|
publishStarted: false,
|
||||||
currentPhase: Constants.PHASE_DETAILS,
|
currentPhase: Constants.PHASE_DETAILS,
|
||||||
showCameraOverlay: false,
|
showCameraOverlay: false,
|
||||||
videoRecordingMode: false,
|
videoRecordingMode: false,
|
||||||
|
@ -597,6 +645,7 @@ class PublishPage extends React.PureComponent {
|
||||||
{
|
{
|
||||||
currentPhase: Constants.PHASE_DETAILS,
|
currentPhase: Constants.PHASE_DETAILS,
|
||||||
currentThumbnailUri: null,
|
currentThumbnailUri: null,
|
||||||
|
publishStarted: false,
|
||||||
updatingThumbnailUri: false,
|
updatingThumbnailUri: false,
|
||||||
showCameraOverlay: false,
|
showCameraOverlay: false,
|
||||||
videoRecordingMode: false,
|
videoRecordingMode: false,
|
||||||
|
@ -701,7 +750,7 @@ class PublishPage extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { notify, uploadThumbnail } = this.props;
|
const { notify } = this.props;
|
||||||
const { thumbnailPath } = this.state;
|
const { thumbnailPath } = this.state;
|
||||||
|
|
||||||
this.setState({ updatingThumbnailUri: true });
|
this.setState({ updatingThumbnailUri: true });
|
||||||
|
@ -716,7 +765,13 @@ class PublishPage extends React.PureComponent {
|
||||||
|
|
||||||
// upload the thumbnail
|
// upload the thumbnail
|
||||||
if (!this.state.uploadedThumbnailUri) {
|
if (!this.state.uploadedThumbnailUri) {
|
||||||
this.setState({ uploadThumbnailStarted: true }, () => uploadThumbnail(this.getFilePathFromUri(uri), RNFS));
|
this.setState({ uploadThumbnailStarted: true }, () =>
|
||||||
|
uploadImageAsset(
|
||||||
|
this.getFilePathFromUri(uri),
|
||||||
|
this.handleThumbnailUploadSuccess,
|
||||||
|
this.handleThumbnailUploadFailure
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (mediaType === 'image' || mediaType === 'video') {
|
} else if (mediaType === 'image' || mediaType === 'video') {
|
||||||
const create =
|
const create =
|
||||||
|
@ -727,7 +782,9 @@ class PublishPage extends React.PureComponent {
|
||||||
.then(path => {
|
.then(path => {
|
||||||
this.setState({ currentThumbnailUri: `file://${path}`, updatingThumbnailUri: false });
|
this.setState({ currentThumbnailUri: `file://${path}`, updatingThumbnailUri: false });
|
||||||
if (!this.state.uploadedThumbnailUri) {
|
if (!this.state.uploadedThumbnailUri) {
|
||||||
this.setState({ uploadThumbnailStarted: true }, () => uploadThumbnail(path, RNFS));
|
this.setState({ uploadThumbnailStarted: true }, () =>
|
||||||
|
uploadImageAsset(path, this.handleThumbnailUploadSuccess, this.handleThumbnailUploadFailure)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
@ -783,7 +840,7 @@ class PublishPage extends React.PureComponent {
|
||||||
: '';
|
: '';
|
||||||
const licenseUrl = LICENSES.CC_LICENSES.reduce((value, item) => {
|
const licenseUrl = LICENSES.CC_LICENSES.reduce((value, item) => {
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
value = '';
|
value = license === value.value ? item.url : '';
|
||||||
}
|
}
|
||||||
if (license === item.value) {
|
if (license === item.value) {
|
||||||
value = item.url;
|
value = item.url;
|
||||||
|
@ -801,6 +858,25 @@ class PublishPage extends React.PureComponent {
|
||||||
this.setState({ otherLicenseDescription });
|
this.setState({ otherLicenseDescription });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleThumbnailPressed = () => {
|
||||||
|
const { notify } = this.props;
|
||||||
|
if (this.state.thumbnailImagePickerOpen || this.state.uploadThumbnailStarted) {
|
||||||
|
if (this.state.uploadThumbnailStarted) {
|
||||||
|
notify({ message: 'A thumbnail is already being uploaded. Please wait for the upload to finish.' });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
thumbnailImagePickerOpen: true,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
NativeModules.UtilityModule.openDocumentPicker('image/*');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { balance, navigation, notify, publishFormValues } = this.props;
|
const { balance, navigation, notify, publishFormValues } = this.props;
|
||||||
const {
|
const {
|
||||||
|
@ -895,22 +971,24 @@ class PublishPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
content = (
|
content = (
|
||||||
<ScrollView style={publishStyle.publishDetails}>
|
<ScrollView style={publishStyle.publishDetails}>
|
||||||
{currentThumbnailUri && currentThumbnailUri.trim().length > 0 && (
|
<TouchableOpacity style={publishStyle.mainThumbnailContainer} onPress={this.handleThumbnailPressed}>
|
||||||
<View style={publishStyle.mainThumbnailContainer}>
|
<FastImage
|
||||||
<FastImage
|
style={publishStyle.mainThumbnail}
|
||||||
style={publishStyle.mainThumbnail}
|
resizeMode={FastImage.resizeMode.contain}
|
||||||
resizeMode={FastImage.resizeMode.contain}
|
source={{ uri: currentThumbnailUri }}
|
||||||
source={{ uri: currentThumbnailUri }}
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
{this.state.uploadThumbnailStarted && !this.state.uploadedThumbnailUri && (
|
<View style={publishStyle.thumbnailEditOverlay}>
|
||||||
<View style={publishStyle.thumbnailUploadContainer}>
|
<Icon name={'edit'} style={publishStyle.editIcon} />
|
||||||
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
|
||||||
<Text style={publishStyle.thumbnailUploadText}>Uploading thumbnail...</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
|
{this.state.uploadThumbnailStarted && (
|
||||||
|
<View style={publishStyle.thumbnailUploadContainer}>
|
||||||
|
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
||||||
|
<Text style={publishStyle.thumbnailUploadText}>Uploading thumbnail...</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
{!this.state.canPublish && <PublishRewardsDriver navigation={navigation} />}
|
{!this.state.canPublish && <PublishRewardsDriver navigation={navigation} />}
|
||||||
|
|
||||||
<View style={publishStyle.card}>
|
<View style={publishStyle.card}>
|
||||||
|
@ -1107,17 +1185,17 @@ class PublishPage extends React.PureComponent {
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={publishStyle.actionButtons}>
|
<View style={publishStyle.actionButtons}>
|
||||||
{(this.state.publishStarted || publishFormValues.publishing) && (
|
{this.state.publishStarted && (
|
||||||
<View style={publishStyle.progress}>
|
<View style={publishStyle.progress}>
|
||||||
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!publishFormValues.publishing && !this.state.publishStarted && (
|
{!this.state.publishStarted && (
|
||||||
<Link style={publishStyle.cancelLink} text="Cancel" onPress={() => this.showSelector()} />
|
<Link style={publishStyle.cancelLink} text="Cancel" onPress={() => this.showSelector()} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!publishFormValues.publishing && !this.state.publishStarted && (
|
{!this.state.publishStarted && (
|
||||||
<View style={publishStyle.rightActionButtons}>
|
<View style={publishStyle.rightActionButtons}>
|
||||||
<Button
|
<Button
|
||||||
style={publishStyle.publishButton}
|
style={publishStyle.publishButton}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { ActivityIndicator, Alert, FlatList, NativeModules, Text, TouchableOpaci
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import FileListItem from 'component/fileListItem';
|
import FileListItem from 'component/fileListItem';
|
||||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
import UriBar from 'component/uriBar';
|
import UriBar from 'component/uriBar';
|
||||||
|
@ -137,16 +138,11 @@ class PublishesPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!fetching && (!uris || uris.length === 0) && (
|
{!fetching && (!uris || uris.length === 0) && (
|
||||||
<View style={publishStyle.noPublishes}>
|
<EmptyStateView
|
||||||
<Text style={publishStyle.noPublishText}>
|
message={__('It looks like you have not\npublished any content to LBRY yet.')}
|
||||||
{__('It looks like you have not published anything to LBRY yet.')}
|
buttonText={__('Publish something new')}
|
||||||
</Text>
|
onButtonPress={() => navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH })}
|
||||||
<Button
|
/>
|
||||||
style={publishStyle.publishNowButton}
|
|
||||||
text={__('Publish something new')}
|
|
||||||
onPress={() => navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH })}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{uris && uris.length > 0 && (
|
{uris && uris.length > 0 && (
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import { ActivityIndicator, NativeModules, View, ScrollView, Text } from 'react-native';
|
import { ActivityIndicator, NativeModules, View, ScrollView, Text } from 'react-native';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
import TransactionList from 'component/transactionList';
|
import TransactionList from 'component/transactionList';
|
||||||
import UriBar from 'component/uriBar';
|
import UriBar from 'component/uriBar';
|
||||||
import walletStyle from 'styles/wallet';
|
import walletStyle from 'styles/wallet';
|
||||||
|
@ -53,11 +54,9 @@ class TransactionHistoryPage extends React.PureComponent {
|
||||||
<Text style={walletStyle.loadingText}>Loading transactions...</Text>
|
<Text style={walletStyle.loadingText}>Loading transactions...</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
{!fetchingTransactions && transactions.length === 0 && <EmptyStateView message={'No transactions to list.'} />}
|
||||||
<ScrollView style={walletStyle.transactionHistoryScroll}>
|
<ScrollView style={walletStyle.transactionHistoryScroll}>
|
||||||
<View style={walletStyle.historyList}>
|
<View style={walletStyle.historyList}>
|
||||||
{!fetchingTransactions && transactions.length === 0 && (
|
|
||||||
<Text style={walletStyle.infoText}>No transactions to list.</Text>
|
|
||||||
)}
|
|
||||||
{!fetchingTransactions && transactions && transactions.length > 0 && (
|
{!fetchingTransactions && transactions && transactions.length > 0 && (
|
||||||
<TransactionList navigation={navigation} transactions={transactions} />
|
<TransactionList navigation={navigation} transactions={transactions} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class SyncVerifyPage extends React.PureComponent {
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
syncApply(syncHash, syncData, this.state.password);
|
syncApply(syncHash, syncData, this.state.password ? this.state.password : '');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -121,7 +121,7 @@ const channelCreatorStyle = StyleSheet.create({
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
listFooter: {
|
listFooter: {
|
||||||
marginTop: 24,
|
marginTop: 8,
|
||||||
},
|
},
|
||||||
createChannelButton: {
|
createChannelButton: {
|
||||||
backgroundColor: Colors.LbryGreen,
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
@ -254,6 +254,15 @@ const channelCreatorStyle = StyleSheet.create({
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
},
|
},
|
||||||
|
loading: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default channelCreatorStyle;
|
export default channelCreatorStyle;
|
||||||
|
|
|
@ -169,6 +169,9 @@ const channelPageStyle = StyleSheet.create({
|
||||||
actionButton: {
|
actionButton: {
|
||||||
backgroundColor: Colors.White,
|
backgroundColor: Colors.White,
|
||||||
},
|
},
|
||||||
|
deleteButton: {
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default channelPageStyle;
|
export default channelPageStyle;
|
||||||
|
|
40
src/styles/emptyState.js
Normal file
40
src/styles/emptyState.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import Colors from './colors';
|
||||||
|
|
||||||
|
const emptyStateStyle = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
paddingLeft: 24,
|
||||||
|
paddingRight: 24,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
zIndex: 99,
|
||||||
|
},
|
||||||
|
outerContainer: {
|
||||||
|
top: 60,
|
||||||
|
},
|
||||||
|
innerContainer: {
|
||||||
|
top: 0,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: 128,
|
||||||
|
height: 170,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
marginTop: 24,
|
||||||
|
textAlign: 'center',
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 18,
|
||||||
|
lineHeight: 28,
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default emptyStateStyle;
|
|
@ -1,6 +1,9 @@
|
||||||
import { StyleSheet } from 'react-native';
|
import { Dimensions, StyleSheet } from 'react-native';
|
||||||
import Colors from './colors';
|
import Colors from './colors';
|
||||||
|
|
||||||
|
const screenDimension = Dimensions.get('window');
|
||||||
|
const screenWidth = screenDimension.width;
|
||||||
|
|
||||||
const publishStyle = StyleSheet.create({
|
const publishStyle = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -434,7 +437,7 @@ const publishStyle = StyleSheet.create({
|
||||||
color: Colors.DescriptionGrey,
|
color: Colors.DescriptionGrey,
|
||||||
},
|
},
|
||||||
publishesFooter: {
|
publishesFooter: {
|
||||||
marginTop: 16,
|
marginTop: 2,
|
||||||
marginLeft: 16,
|
marginLeft: 16,
|
||||||
marginRight: 16,
|
marginRight: 16,
|
||||||
},
|
},
|
||||||
|
@ -443,6 +446,21 @@ const publishStyle = StyleSheet.create({
|
||||||
backgroundColor: Colors.LbryGreen,
|
backgroundColor: Colors.LbryGreen,
|
||||||
marginTop: 16,
|
marginTop: 16,
|
||||||
},
|
},
|
||||||
|
thumbnailEditOverlay: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
borderRadius: 24,
|
||||||
|
position: 'absolute',
|
||||||
|
padding: 8,
|
||||||
|
left: screenWidth / 2 - 32 / 2,
|
||||||
|
bottom: 8,
|
||||||
|
backgroundColor: '#00000077',
|
||||||
|
},
|
||||||
|
editIcon: {
|
||||||
|
color: Colors.White,
|
||||||
|
fontFamily: 'Inter-UI-SemiBold',
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default publishStyle;
|
export default publishStyle;
|
||||||
|
|
Loading…
Reference in a new issue