Repost creation #133

Merged
akinwale merged 7 commits from repost-creation into master 2020-03-20 14:21:18 +01:00
8 changed files with 306 additions and 13 deletions
Showing only changes of commit 1df7e617eb - Show all commits

@ -1 +1 @@
Subproject commit 56c375f344911bffe64c0564dd37d2bb8b7761f1 Subproject commit e9c8f9432f0966240670695792257b16ceaaac32

View file

@ -1,15 +1,28 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doSendTip, doToast, selectBalance } from 'lbry-redux'; import {
doClearRepostError,
doFetchChannelListMine,
doRepost,
doToast,
selectBalance,
selectMyChannelClaims,
selectRepostError,
selectRepostLoading,
} from 'lbry-redux';
import ModalRepostView from './view'; import ModalRepostView from './view';
const select = state => ({ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
channels: selectMyChannelClaims(state),
reposting: selectRepostLoading(state),
error: selectRepostError(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)),
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
sendTip: (amount, claimId, isSupport, successCallback, errorCallback) => repost: options => dispatch(doRepost(options)),
dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)), clearError: () => dispatch(doClearRepostError()),
}); });
export default connect(select, perform)(ModalRepostView); export default connect(select, perform)(ModalRepostView);

View file

@ -1,14 +1,187 @@
import React from 'react'; import React from 'react';
import { ActivityIndicator, Alert, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Alert, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { formatCredits } from 'lbry-redux'; import { formatCredits, creditsToString } from 'lbry-redux';
import modalStyle from 'styles/modal'; import modalStyle from 'styles/modal';
import modalTipStyle from 'styles/modalTip'; import modalRepostStyle from 'styles/modalRepost';
import ChannelSelector from 'component/channelSelector';
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 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 { logPublish } from 'utils/helper';
export default class ModalRepostView extends React.PureComponent { export default class ModalRepostView extends React.PureComponent {
render() {} depositAmountInput;
state = {
repostName: null,
channelName: null,
creditsInputFocused: false,
depositAmount: '0.1',
repostStarted: false,
};
componentDidMount() {
const { claim, fetchChannelListMine } = this.props;
const { name } = claim;
fetchChannelListMine();
this.setState({ repostName: name });
this.checkChannelSelection(this.props);
}
componentWillReceiveProps(nextProps) {
this.checkChannelSelection(nextProps);
const { notify } = this.props;
const { reposting, error } = nextProps;
if (this.state.repostStarted && !reposting && error) {
this.setState({ repostStarted: false });
notify({ message: error, isError: true });
}
}
checkChannelSelection = props => {
const { channels = [] } = props;
if (!this.state.channelName && channels && channels.length > 0) {
const firstChannel = channels[0];
this.setState({ channelName: firstChannel.name });
}
};
handleChannelChange = channelName => {
const { channels = [] } = this.props;
if (channels && channels.length > 0) {
const filtered = channels.filter(c => c.name === channelName);
if (filtered.length > 0) {
const channel = filtered[0];
this.setState({ channelName });
}
}
};
handleRepost = () => {
const { claim, balance, notify, repost, onRepostSuccessful, channels = [], clearError } = this.props;
const { depositAmount, repostName, channelName } = this.state;
if (parseInt(depositAmount, 10) > balance) {
notify({
message: 'Insufficient credits',
isError: true,
});
return;
}
clearError();
const channel = channels.filter(ch => ch.name === channelName)[0];
this.setState({ repostStarted: true }, () => {
repost({
name: repostName,
bid: creditsToString(depositAmount),
channel_id: channel.claim_id,
claim_id: claim.claim_id,
}).then(repostClaim => {
logPublish(repostClaim);
this.setState({ repostStarted: false });
notify({ message: __('The content was successfully reposted!') });
if (onRepostSuccessful) onRepostSuccessful();
});
});
};
render() {
const { balance, channels, reposting, title, onCancelPress, onOverlayPress } = this.props;
const canRepost = !!this.state.channelName && !!this.state.repostName;
const channelsLoaded = channels && channels.length > 0;
return (
<TouchableOpacity style={modalStyle.overlay} activeOpacity={1} onPress={onOverlayPress}>
<TouchableOpacity style={modalStyle.container} activeOpacity={1}>
<View
style={modalRepostStyle.container}
onLayout={() => {
if (this.tipAmountInput) {
this.tipAmountInput.focus();
}
}}
>
<Text style={modalRepostStyle.title} numberOfLines={1}>
{__('Repost %title%', { title })}
</Text>
<Text style={modalRepostStyle.infoText}>
{__('Repost your favorite content to help more people discover them!')}
</Text>
<Text style={modalRepostStyle.label}>{__('Channel to post on')}</Text>
<ChannelSelector
showAnonymous={false}
channelName={this.state.channelName}
onChannelChange={this.handleChannelChange}
/>
<Text style={modalRepostStyle.label}>{__('Name')}</Text>
<View style={modalRepostStyle.nameRow}>
<TextInput
editable={false}
value={this.state.channelName ? `lbry://${this.state.channelName}/` : ''}
style={modalRepostStyle.input}
/>
<TextInput
editable={canRepost}
value={this.state.repostName}
underlineColorAndroid={Colors.NextLbryGreen}
selectTextOnFocus
onChangeText={value => this.setState({ repostName: value })}
style={modalRepostStyle.input}
/>
</View>
<Text style={modalRepostStyle.label}>{__('Deposit')}</Text>
<View style={modalRepostStyle.row}>
<View style={modalRepostStyle.amountRow}>
<TextInput
editable={!this.state.repostStarted}
ref={ref => (this.depositAmountInput = ref)}
onChangeText={value => this.setState({ tipAmount: value })}
underlineColorAndroid={Colors.NextLbryGreen}
keyboardType={'numeric'}
onFocus={() => this.setState({ creditsInputFocused: true })}
onBlur={() => this.setState({ creditsInputFocused: false })}
placeholder={'0'}
value={this.state.depositAmount}
selectTextOnFocus
style={modalRepostStyle.depositAmountInput}
/>
<Text style={modalRepostStyle.currency}>LBC</Text>
<View style={modalRepostStyle.balance}>
{this.state.creditsInputFocused && <Icon name="coins" size={12} />}
{this.state.creditsInputFocused && (
<Text style={modalRepostStyle.balanceText}>{formatCredits(parseFloat(balance), 1, true)}</Text>
)}
</View>
</View>
{(this.state.repostStarted || reposting || !channelsLoaded) && (
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
)}
</View>
<View style={modalRepostStyle.buttonRow}>
<Link
style={modalRepostStyle.cancelLink}
text={__('Cancel')}
onPress={() => {
if (onCancelPress) onCancelPress();
}}
/>
<Button
text={__('Repost')}
style={modalRepostStyle.button}
disabled={!canRepost || this.state.repostStarted || reposting}
onPress={this.handleRepost}
/>
</View>
</View>
</TouchableOpacity>
</TouchableOpacity>
);
}
} }

View file

@ -5,7 +5,6 @@ import modalStyle from 'styles/modal';
import modalTipStyle from 'styles/modalTip'; import modalTipStyle from 'styles/modalTip';
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 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';
@ -25,6 +24,7 @@ export default class ModalTipView extends React.PureComponent {
if (tipAmount > balance) { if (tipAmount > balance) {
notify({ notify({
message: 'Insufficient credits', message: 'Insufficient credits',
isError: true,
}); });
return; return;
} }
@ -56,13 +56,13 @@ export default class ModalTipView extends React.PureComponent {
() => { () => {
// error // error
if (onSendTipFailed) onSendTipFailed(); if (onSendTipFailed) onSendTipFailed();
} },
) ),
); );
}, },
}, },
], ],
{ cancelable: true } { cancelable: true },
); );
}; };
@ -115,7 +115,7 @@ export default class ModalTipView extends React.PureComponent {
<Text style={modalTipStyle.infoText}> <Text style={modalTipStyle.infoText}>
{__( {__(
'This will appear as a tip for %content%, which will boost its ability to be discovered while active.', 'This will appear as a tip for %content%, which will boost its ability to be discovered while active.',
{ content: contentName } { content: contentName },
)}{' '} )}{' '}
<Link <Link
style={modalTipStyle.learnMoreLink} style={modalTipStyle.learnMoreLink}

View file

@ -149,7 +149,7 @@ const Constants = {
TRUE_STRING: 'true', TRUE_STRING: 'true',
MINIMUM_TRANSACTION_BALANCE: 0.1, MINIMUM_TRANSACTION_BALANCE: 0.01,
SHARE_BASE_URL: 'https://open.lbry.com', SHARE_BASE_URL: 'https://open.lbry.com',
}; };

View file

@ -37,6 +37,7 @@ import FilePrice from 'component/filePrice';
import FloatingWalletBalance from 'component/floatingWalletBalance'; import FloatingWalletBalance from 'component/floatingWalletBalance';
import Link from 'component/link'; import Link from 'component/link';
import MediaPlayer from 'component/mediaPlayer'; import MediaPlayer from 'component/mediaPlayer';
import ModalRepostView from 'component/modalRepostView';
import ModalTipView from 'component/modalTipView'; import ModalTipView from 'component/modalTipView';
import ProgressCircle from 'react-native-progress-circle'; import ProgressCircle from 'react-native-progress-circle';
import RelatedContent from 'component/relatedContent'; import RelatedContent from 'component/relatedContent';
@ -94,6 +95,7 @@ class FilePage extends React.PureComponent {
showImageViewer: false, showImageViewer: false,
showWebView: false, showWebView: false,
showTipView: false, showTipView: false,
showRepostView: false,
playbackStarted: false, playbackStarted: false,
playerBgHeight: 0, playerBgHeight: 0,
playerHeight: 0, playerHeight: 0,
@ -265,6 +267,7 @@ class FilePage extends React.PureComponent {
'playerBgHeighht', 'playerBgHeighht',
'playerHeight', 'playerHeight',
'relatedY', 'relatedY',
'showRepostView',
'showTipView', 'showTipView',
'showImageViewer', 'showImageViewer',
'showWebView', 'showWebView',
@ -1348,6 +1351,14 @@ class FilePage extends React.PureComponent {
<Text style={filePageStyle.largeButtonText}>{__('Share')}</Text> <Text style={filePageStyle.largeButtonText}>{__('Share')}</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity
style={filePageStyle.largeButton}
onPress={() => this.setState({ showRepostView: true })}
>
<Icon name={'retweet'} size={16} style={filePageStyle.largeButtonIcon} />
<Text style={filePageStyle.largeButtonText}>{__('Repost')}</Text>
</TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={filePageStyle.largeButton} style={filePageStyle.largeButton}
onPress={() => this.setState({ showTipView: true })} onPress={() => this.setState({ showTipView: true })}
@ -1522,7 +1533,17 @@ class FilePage extends React.PureComponent {
onSendTipSuccessful={() => this.setState({ showTipView: false })} onSendTipSuccessful={() => this.setState({ showTipView: false })}
/> />
)} )}
{this.state.showRepostView && (
<ModalRepostView
claim={claim}
title={title}
onCancelPress={() => this.setState({ showRepostView: false })}
onOverlayPress={() => this.setState({ showRepostView: false })}
onRepostSuccessful={() => this.setState({ showRepostView: false })}
/>
)}
{!this.state.fullscreenMode && {!this.state.fullscreenMode &&
!this.state.showRepostView &&
!this.state.showTipView && !this.state.showTipView &&
!this.state.showImageViewer && !this.state.showImageViewer &&
!this.state.showWebView && <FloatingWalletBalance navigation={navigation} />} !this.state.showWebView && <FloatingWalletBalance navigation={navigation} />}

View file

@ -322,6 +322,7 @@ class SplashScreen extends React.PureComponent {
componentDidMount() { componentDidMount() {
NativeModules.Firebase.track('app_launch', null); NativeModules.Firebase.track('app_launch', null);
NativeModules.Firebase.setCurrentScreen('Splash'); NativeModules.Firebase.setCurrentScreen('Splash');
NativeModules.UtilityModule.checkSdkReady();
const { navigation } = this.props; const { navigation } = this.props;
const { resetUrl } = navigation.state.params; const { resetUrl } = navigation.state.params;

85
src/styles/modalRepost.js Normal file
View file

@ -0,0 +1,85 @@
import { StyleSheet } from 'react-native';
import Colors from './colors';
const modalRepostStyle = StyleSheet.create({
container: {
padding: 16,
},
title: {
fontFamily: 'Inter-Regular',
fontSize: 24,
marginBottom: 8,
},
row: {
flexDirection: 'row',
flex: 1,
},
amountRow: {
flexDirection: 'row',
alignItems: 'center',
marginRight: 24,
},
depositAmountInput: {
fontFamily: 'Inter-Regular',
fontSize: 14,
alignSelf: 'flex-start',
textAlign: 'right',
width: 80,
letterSpacing: 1,
},
currency: {
fontFamily: 'Inter-Regular',
fontSize: 12,
marginLeft: 4,
},
buttonRow: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 16,
},
button: {
backgroundColor: Colors.LbryGreen,
},
cancelLink: {
color: Colors.Grey,
},
balance: {
alignItems: 'center',
flexDirection: 'row',
marginLeft: 24,
},
balanceText: {
fontFamily: 'Inter-SemiBold',
fontSize: 14,
marginLeft: 4,
},
info: {
marginTop: 4,
},
infoText: {
fontFamily: 'Inter-Regular',
fontSize: 14,
color: Colors.DescriptionGrey,
},
learnMoreLink: {
fontFamily: 'Inter-Regular',
fontSize: 14,
color: Colors.LbryGreen,
},
label: {
fontFamily: 'Inter-Regular',
fontSize: 14,
marginTop: 8,
},
nameRow: {
flexDirection: 'row',
alignItems: 'center',
},
input: {
fontFamily: 'Inter-Regular',
fontSize: 14,
},
});
export default modalRepostStyle;