implement send tip functionality #366
5 changed files with 126 additions and 26 deletions
|
@ -8,15 +8,15 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import WalletSend from './view';
|
import WalletSend from './view';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
|
||||||
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
|
||||||
notify: (data) => dispatch(doToast(data))
|
|
||||||
});
|
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
balance: selectBalance(state),
|
balance: selectBalance(state),
|
||||||
draftTransaction: selectDraftTransaction(state),
|
draftTransaction: selectDraftTransaction(state),
|
||||||
transactionError: selectDraftTransactionError(state),
|
transactionError: selectDraftTransactionError(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
||||||
|
notify: (data) => dispatch(doToast(data))
|
||||||
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(WalletSend);
|
export default connect(select, perform)(WalletSend);
|
||||||
|
|
|
@ -37,7 +37,7 @@ const globalExceptionHandler = (error, isFatal) => {
|
||||||
NativeModules.Mixpanel.logException(isFatal, error.message ? error.message : "No message", error);
|
NativeModules.Mixpanel.logException(isFatal, error.message ? error.message : "No message", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
setJSExceptionHandler(globalExceptionHandler, true);
|
//setJSExceptionHandler(globalExceptionHandler, true);
|
||||||
|
|
||||||
|
|
||||||
function isFunction(object) {
|
function isFunction(object) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
doFetchFileInfo,
|
doFetchFileInfo,
|
||||||
doFetchCostInfoForUri,
|
doFetchCostInfoForUri,
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
|
doSendTip,
|
||||||
doToast,
|
doToast,
|
||||||
makeSelectIsUriResolving,
|
makeSelectIsUriResolving,
|
||||||
makeSelectCostInfoForUri,
|
makeSelectCostInfoForUri,
|
||||||
|
@ -10,6 +11,7 @@ import {
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
makeSelectContentTypeForUri,
|
makeSelectContentTypeForUri,
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
|
selectBalance,
|
||||||
selectBlackListedOutpoints,
|
selectBlackListedOutpoints,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectRewardContentClaimIds } from 'lbryinc';
|
import { selectRewardContentClaimIds } from 'lbryinc';
|
||||||
|
@ -19,6 +21,7 @@ import FilePage from './view';
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const selectProps = { uri: props.navigation.state.params.uri };
|
const selectProps = { uri: props.navigation.state.params.uri };
|
||||||
return {
|
return {
|
||||||
|
balance: selectBalance(state),
|
||||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||||
claim: makeSelectClaimForUri(selectProps.uri)(state),
|
claim: makeSelectClaimForUri(selectProps.uri)(state),
|
||||||
isResolvingUri: makeSelectIsUriResolving(selectProps.uri)(state),
|
isResolvingUri: makeSelectIsUriResolving(selectProps.uri)(state),
|
||||||
|
@ -40,6 +43,7 @@ const perform = dispatch => ({
|
||||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
sendTip: (amount, claimId, uri, successCallback, errorCallback) => dispatch(doSendTip(amount, claimId, uri, successCallback, errorCallback)),
|
||||||
stopDownload: (uri, fileInfo) => dispatch(doStopDownloadingFile(uri, fileInfo)),
|
stopDownload: (uri, fileInfo) => dispatch(doStopDownloadingFile(uri, fileInfo)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ class FilePage extends React.PureComponent {
|
||||||
title: ''
|
title: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tipAmountInput = null;
|
||||||
|
|
||||||
playerBackground = null;
|
playerBackground = null;
|
||||||
|
|
||||||
startTime = null;
|
startTime = null;
|
||||||
|
@ -55,8 +57,10 @@ class FilePage extends React.PureComponent {
|
||||||
pageSuspended: false,
|
pageSuspended: false,
|
||||||
showImageViewer: false,
|
showImageViewer: false,
|
||||||
showWebView: false,
|
showWebView: false,
|
||||||
|
showTipView: false,
|
||||||
playerBgHeight: 0,
|
playerBgHeight: 0,
|
||||||
playerHeight: 0,
|
playerHeight: 0,
|
||||||
|
tipAmount: null,
|
||||||
uri: null,
|
uri: null,
|
||||||
stopDownloadConfirmed: false
|
stopDownloadConfirmed: false
|
||||||
};
|
};
|
||||||
|
@ -177,7 +181,7 @@ class FilePage extends React.PureComponent {
|
||||||
[
|
[
|
||||||
{ text: 'No' },
|
{ text: 'No' },
|
||||||
{ text: 'Yes', onPress: () => {
|
{ text: 'Yes', onPress: () => {
|
||||||
stopDownload(navigation.state.params.uri, fileInfo);
|
stopDownloadz4(navigation.state.params.uri, fileInfo);
|
||||||
this.setState({
|
this.setState({
|
||||||
downloadPressed: false,
|
downloadPressed: false,
|
||||||
fileViewLogged: false,
|
fileViewLogged: false,
|
||||||
|
@ -310,6 +314,21 @@ class FilePage extends React.PureComponent {
|
||||||
this.setState({ fileViewLogged: true });
|
this.setState({ fileViewLogged: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSendTip = () => {
|
||||||
|
const { claim, balance, navigation, notify, sendTip } = this.props;
|
||||||
|
const { uri } = navigation.state.params;
|
||||||
|
const { tipAmount } = this.state;
|
||||||
|
|
||||||
|
if (tipAmount > balance) {
|
||||||
|
notify({
|
||||||
|
message: 'Insufficient credits',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTip(tipAmount, claim.claim_id, uri, () => { this.setState({ tipAmount: 0, showTipView: false }) });
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
claim,
|
claim,
|
||||||
|
@ -378,12 +397,12 @@ class FilePage extends React.PureComponent {
|
||||||
const mediaType = Lbry.getMediaType(contentType);
|
const mediaType = Lbry.getMediaType(contentType);
|
||||||
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
||||||
const { height, channel_name: channelName, value } = claim;
|
const { height, channel_name: channelName, value } = claim;
|
||||||
const showActions = !this.state.fullscreenMode &&
|
const showActions = !this.state.fullscreenMode && !this.state.showImageViewer && !this.state.showWebView;
|
||||||
!this.state.showImageViewer &&
|
const showFileActions = (completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes));
|
||||||
!this.state.showWebView &&
|
|
||||||
(completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes));
|
|
||||||
const channelClaimId =
|
const channelClaimId =
|
||||||
value && value.publisherSignature && value.publisherSignature.certificateId;
|
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||||
|
const canSendTip = this.state.tipAmount > 0;
|
||||||
|
|
||||||
|
|
||||||
const playerStyle = [filePageStyle.player,
|
const playerStyle = [filePageStyle.player,
|
||||||
this.state.isLandscape ? filePageStyle.containedPlayerLandscape :
|
this.state.isLandscape ? filePageStyle.containedPlayerLandscape :
|
||||||
|
@ -473,8 +492,15 @@ class FilePage extends React.PureComponent {
|
||||||
onPlaybackStarted={this.onPlaybackStarted}
|
onPlaybackStarted={this.onPlaybackStarted}
|
||||||
/>}
|
/>}
|
||||||
|
|
||||||
{fileInfo && showActions &&
|
{showActions &&
|
||||||
<View style={filePageStyle.actions}>
|
<View style={filePageStyle.actions}>
|
||||||
|
{<Button style={filePageStyle.actionButton}
|
||||||
|
theme={"light"}
|
||||||
|
icon={"gift"}
|
||||||
|
text={"Send a tip"}
|
||||||
|
onPress={() => this.setState({ showTipView: true })} />}
|
||||||
|
{showFileActions &&
|
||||||
|
<View style={filePageStyle.fileActions}>
|
||||||
{completed && <Button style={filePageStyle.actionButton}
|
{completed && <Button style={filePageStyle.actionButton}
|
||||||
theme={"light"}
|
theme={"light"}
|
||||||
icon={"trash"}
|
icon={"trash"}
|
||||||
|
@ -489,6 +515,7 @@ class FilePage extends React.PureComponent {
|
||||||
onPress={this.onStopDownloadPressed} />
|
onPress={this.onStopDownloadPressed} />
|
||||||
}
|
}
|
||||||
</View>}
|
</View>}
|
||||||
|
</View>}
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}
|
style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}
|
||||||
contentContainerstyle={showActions ? null : filePageStyle.scrollContent}>
|
contentContainerstyle={showActions ? null : filePageStyle.scrollContent}>
|
||||||
|
@ -507,6 +534,23 @@ class FilePage extends React.PureComponent {
|
||||||
|
|
||||||
<RelatedContent navigation={navigation} uri={uri} />
|
<RelatedContent navigation={navigation} uri={uri} />
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
{this.state.showTipView && <View style={filePageStyle.tipCard}>
|
||||||
|
<View style={filePageStyle.row}>
|
||||||
|
<View style={filePageStyle.amountRow}>
|
||||||
|
<TextInput ref={ref => this.tipAmountInput = ref}
|
||||||
|
onChangeText={value => this.setState({tipAmount: value})}
|
||||||
|
keyboardType={'numeric'}
|
||||||
|
value={this.state.tipAmount}
|
||||||
|
style={[filePageStyle.input, filePageStyle.tipAmountInput]} />
|
||||||
|
<Text style={[filePageStyle.text, filePageStyle.currency]}>LBC</Text>
|
||||||
|
</View>
|
||||||
|
<Link style={[filePageStyle.link, filePageStyle.cancelTipLink]} text={'Cancel'} onPress={() => this.setState({ showTipView: false })} />
|
||||||
|
<Button text={'Send tip'}
|
||||||
|
style={[filePageStyle.button, filePageStyle.sendButton]}
|
||||||
|
disabled={!canSendTip}
|
||||||
|
onPress={this.handleSendTip} />
|
||||||
|
</View>
|
||||||
|
</View>}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{!this.state.fullscreenMode && <FloatingWalletBalance navigation={navigation} />}
|
{!this.state.fullscreenMode && <FloatingWalletBalance navigation={navigation} />}
|
||||||
|
|
|
@ -142,6 +142,8 @@ const filePageStyle = StyleSheet.create({
|
||||||
color: '#0c604b'
|
color: '#0c604b'
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
paddingLeft: 16,
|
paddingLeft: 16,
|
||||||
paddingRight: 16,
|
paddingRight: 16,
|
||||||
paddingTop: 16,
|
paddingTop: 16,
|
||||||
|
@ -149,6 +151,9 @@ const filePageStyle = StyleSheet.create({
|
||||||
marginTop: -14,
|
marginTop: -14,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
|
fileActions: {
|
||||||
|
alignSelf: 'flex-end'
|
||||||
|
},
|
||||||
actionButton: {
|
actionButton: {
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
backgroundColor: Colors.White,
|
backgroundColor: Colors.White,
|
||||||
|
@ -200,10 +205,57 @@ const filePageStyle = StyleSheet.create({
|
||||||
zIndex: 100
|
zIndex: 100
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
color: Colors.LbryGreen
|
color: Colors.Grey
|
||||||
},
|
},
|
||||||
linkTapped: {
|
linkTapped: {
|
||||||
color: "rgba(64, 184, 154, .2)"
|
color: "rgba(64, 184, 154, .2)"
|
||||||
|
},
|
||||||
|
tipCard: {
|
||||||
|
backgroundColor: Colors.White,
|
||||||
|
position: 'absolute',
|
||||||
|
top: containedMediaHeightWithControls - 16,
|
||||||
|
width: '100%',
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingBottom: 8,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
|
amountRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flex: 0.75
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
marginBottom: 6
|
||||||
|
},
|
||||||
|
cancelTipLink: {
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
marginBottom: 14
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
tipAmountInput: {
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
width: 80,
|
||||||
|
fontSize: 16,
|
||||||
|
letterSpacing: 1
|
||||||
|
},
|
||||||
|
currency: {
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
marginTop: 17
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 16,
|
||||||
|
lineHeight: 24
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue