updates for patch release #106
9 changed files with 130 additions and 47 deletions
|
@ -30,7 +30,6 @@ class FileDownloadButton extends React.PureComponent {
|
|||
fileInfo,
|
||||
downloading,
|
||||
uri,
|
||||
purchaseUri,
|
||||
costInfo,
|
||||
isPlayable,
|
||||
isViewable,
|
||||
|
|
|
@ -36,5 +36,5 @@ const perform = dispatch => ({
|
|||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
perform,
|
||||
)(FileListItem);
|
||||
|
|
|
@ -6,6 +6,7 @@ import Colors from 'styles/colors';
|
|||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||
import DateTime from 'component/dateTime';
|
||||
import FileItemMedia from 'component/fileItemMedia';
|
||||
import FilePrice from 'component/filePrice';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
import Link from 'component/link';
|
||||
import NsfwOverlay from 'component/nsfwOverlay';
|
||||
|
@ -42,7 +43,6 @@ class FileListItem extends React.PureComponent {
|
|||
componentDidMount() {
|
||||
const { claim, resolveUri, uri, batchResolve } = this.props;
|
||||
if (!claim && !batchResolve) {
|
||||
console.log('resolving on componentDidMount?');
|
||||
resolveUri(uri);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ class FileListItem extends React.PureComponent {
|
|||
componentDidUpdate() {
|
||||
const { claim, resolveUri, uri, batchResolve } = this.props;
|
||||
if (!claim && uri !== this.state.url && !batchResolve) {
|
||||
console.log('resolving on componentDidUpdate?');
|
||||
this.setState({ url: uri }, () => resolveUri(uri));
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +167,7 @@ class FileListItem extends React.PureComponent {
|
|||
size={16}
|
||||
/>
|
||||
)}
|
||||
<FilePrice uri={uri} style={fileListStyle.filePriceContainer} textStyle={fileListStyle.filePriceText} />
|
||||
<View style={fileListStyle.detailsContainer}>
|
||||
{featuredResult && (
|
||||
<Text style={fileListStyle.featuredUri} numberOfLines={1}>
|
||||
|
|
|
@ -46,7 +46,7 @@ class UriBar extends React.PureComponent {
|
|||
const { currentRoute: prevRoute } = this.props;
|
||||
|
||||
if (Constants.DRAWER_ROUTE_SEARCH === currentRoute && currentRoute !== prevRoute) {
|
||||
this.setState({ currentValue: query, inputText: query });
|
||||
this.setState({ currentValue: query, inputText: query }, () => this.setCaretPosition(query));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,9 @@ class UriBar extends React.PureComponent {
|
|||
}
|
||||
}, UriBar.INPUT_TIMEOUT);
|
||||
}
|
||||
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout });
|
||||
this.setState({ inputText: newValue, currentValue: newValue, changeTextTimeout: timeout }, () =>
|
||||
this.setCaretPosition(newValue),
|
||||
);
|
||||
};
|
||||
|
||||
handleItemPress = item => {
|
||||
|
@ -85,7 +87,7 @@ class UriBar extends React.PureComponent {
|
|||
Keyboard.dismiss();
|
||||
|
||||
if (SEARCH_TYPES.SEARCH === type) {
|
||||
this.setState({ currentValue: value });
|
||||
this.setState({ currentValue: value }, () => this.setCaretPosition(value));
|
||||
updateSearchQuery(value);
|
||||
|
||||
if (onSearchSubmitted) {
|
||||
|
@ -129,6 +131,12 @@ class UriBar extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
setCaretPosition(text) {
|
||||
if (this.textInput && text && text.length > 0) {
|
||||
this.textInput.setNativeProps({ selection: { start: text.length, end: text.length } });
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmitEditing = () => {
|
||||
const { navigation, onSearchSubmitted, updateSearchQuery } = this.props;
|
||||
if (this.state.inputText) {
|
||||
|
@ -179,7 +187,7 @@ class UriBar extends React.PureComponent {
|
|||
value,
|
||||
} = this.props;
|
||||
if (this.state.currentValue === null) {
|
||||
this.setState({ currentValue: value });
|
||||
this.setState({ currentValue: value }, () => this.setCaretPosition(value));
|
||||
}
|
||||
|
||||
let style = [
|
||||
|
@ -253,7 +261,9 @@ class UriBar extends React.PureComponent {
|
|||
autoCorrect={false}
|
||||
style={uriBarStyle.uriText}
|
||||
onLayout={() => {
|
||||
this.setSelection();
|
||||
if (!this.state.focused) {
|
||||
this.setSelection();
|
||||
}
|
||||
}}
|
||||
selectTextOnFocus
|
||||
placeholder={__('Search movies, music, and more')}
|
||||
|
|
|
@ -38,9 +38,10 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
handleSend = () => {
|
||||
const { balance, sendToAddress, notify } = this.props;
|
||||
const { address, amount } = this.state;
|
||||
if (address && !regexAddress.test(address)) {
|
||||
if (address && (!regexAddress.test(address) || address.substring(0, 1) === 'r')) {
|
||||
notify({
|
||||
message: __('The recipient address is not a valid LBRY address.'),
|
||||
isError: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -48,6 +49,7 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
if (amount > balance) {
|
||||
notify({
|
||||
message: __('Insufficient credits'),
|
||||
isError: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -72,6 +74,7 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
const { notify } = this.props;
|
||||
notify({
|
||||
message: __('The recipient address is not a valid LBRY address.'),
|
||||
isError: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -97,9 +100,10 @@ class WalletSend extends React.PureComponent<Props> {
|
|||
this.setState({
|
||||
address: value,
|
||||
addressChanged: true,
|
||||
addressValid: value.trim().length === 0 || regexAddress.test(value),
|
||||
addressValid: value.trim().length === 0 || (regexAddress.test(value) && !value.startsWith('r')),
|
||||
})
|
||||
}
|
||||
numberOfLines={1}
|
||||
onBlur={this.handleAddressInputBlur}
|
||||
onSubmitEditing={this.handleAddressInputSubmit}
|
||||
placeholder={'bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs'}
|
||||
|
|
|
@ -113,8 +113,8 @@ class FilePage extends React.PureComponent {
|
|||
|
||||
if (!isResolvingUri && !claim) resolveUri(uri);
|
||||
|
||||
this.fetchFileInfo(this.props);
|
||||
this.fetchCostInfo(this.props);
|
||||
this.fetchFileInfo(uri, this.props);
|
||||
this.fetchCostInfo(uri, this.props);
|
||||
|
||||
fetchMyClaims();
|
||||
|
||||
|
@ -259,21 +259,26 @@ class FilePage extends React.PureComponent {
|
|||
|
||||
// attempt to retrieve images and html/text automatically once the claim is loaded, and it's free
|
||||
const mediaType = Lbry.getMediaType(contentType);
|
||||
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
||||
const isViewable = mediaType === 'image' || mediaType === 'text';
|
||||
if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) {
|
||||
this.setState({ autoGetAttempted: true }, () => this.checkStoragePermissionForDownload());
|
||||
}
|
||||
}
|
||||
|
||||
fetchFileInfo(props) {
|
||||
if (props.fileInfo === undefined) {
|
||||
props.fetchFileInfo(props.navigation.state.params.uri);
|
||||
if (((costInfo && costInfo.cost > 0) || !isPlayable) && !this.state.showRecommended) {
|
||||
this.setState({ showRecommended: true });
|
||||
}
|
||||
}
|
||||
|
||||
fetchCostInfo(props) {
|
||||
fetchFileInfo(uri, props) {
|
||||
if (props.fileInfo === undefined) {
|
||||
props.fetchFileInfo(uri);
|
||||
}
|
||||
}
|
||||
|
||||
fetchCostInfo(uri, props) {
|
||||
if (props.costInfo === undefined) {
|
||||
props.fetchCostInfo(props.navigation.state.params.uri);
|
||||
props.fetchCostInfo(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,12 +313,12 @@ class FilePage extends React.PureComponent {
|
|||
const { abandonClaim, claim, deleteFile, deletePurchasedUri, myClaimUris, fileInfo, navigation } = this.props;
|
||||
|
||||
Alert.alert(
|
||||
'Delete file',
|
||||
'Are you sure you want to remove this file from your device?',
|
||||
__('Delete file'),
|
||||
__('Are you sure you want to remove this file from your device?'),
|
||||
[
|
||||
{ text: 'No' },
|
||||
{ text: __('No') },
|
||||
{
|
||||
text: 'Yes',
|
||||
text: __('Yes'),
|
||||
onPress: () => {
|
||||
const { uri } = navigation.state.params;
|
||||
|
||||
|
@ -598,6 +603,38 @@ class FilePage extends React.PureComponent {
|
|||
));
|
||||
};
|
||||
|
||||
confirmPurchaseUri = (uri, costInfo, download) => {
|
||||
const { notify, purchaseUri, title } = this.props;
|
||||
const { cost } = costInfo;
|
||||
|
||||
if (!costInfo) {
|
||||
notify({ message: __('This content cannot be viewed at this time. Please try again in a bit.'), isError: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (costInfo.cost > 0) {
|
||||
Alert.alert(
|
||||
__('Confirm Purchase'),
|
||||
__(
|
||||
cost === 1
|
||||
? 'This will purchase "%title%" for %amount% credit'
|
||||
: 'This will purchase "%title%" for %amount% credits',
|
||||
{ title, amount: cost },
|
||||
),
|
||||
[
|
||||
{
|
||||
text: __('OK'),
|
||||
onPress: () => purchaseUri(uri, costInfo, download),
|
||||
},
|
||||
{ text: __('Cancel') },
|
||||
],
|
||||
);
|
||||
} else {
|
||||
// Free content. Just call purchaseUri directly.
|
||||
purchaseUri(uri, costInfo, download);
|
||||
}
|
||||
};
|
||||
|
||||
onFileDownloadButtonPressed = () => {
|
||||
const { claim, costInfo, contentType, purchaseUri, setPlayerVisible } = this.props;
|
||||
const mediaType = Lbry.getMediaType(contentType);
|
||||
|
@ -610,7 +647,7 @@ class FilePage extends React.PureComponent {
|
|||
if (!isPlayable) {
|
||||
this.checkStoragePermissionForDownload();
|
||||
} else {
|
||||
purchaseUri(uri, costInfo, !isPlayable);
|
||||
this.confirmPurchaseUri(uri, costInfo, !isPlayable);
|
||||
}
|
||||
|
||||
if (isPlayable) {
|
||||
|
@ -648,7 +685,7 @@ class FilePage extends React.PureComponent {
|
|||
stopDownloadConfirmed: false,
|
||||
},
|
||||
() => {
|
||||
purchaseUri(claim.permanent_url, costInfo, true);
|
||||
this.confirmPurchaseUri(claim.permanent_url, costInfo, true);
|
||||
NativeModules.UtilityModule.checkDownloads();
|
||||
},
|
||||
);
|
||||
|
@ -862,7 +899,7 @@ class FilePage extends React.PureComponent {
|
|||
if (!isPlayable) {
|
||||
this.checkStoragePermissionForDownload();
|
||||
} else {
|
||||
purchaseUri(claim.permanent_url, costInfo, !isPlayable);
|
||||
this.confirmPurchaseUri(claim.permanent_url, costInfo, !isPlayable);
|
||||
}
|
||||
NativeModules.UtilityModule.checkDownloads();
|
||||
});
|
||||
|
@ -950,7 +987,11 @@ class FilePage extends React.PureComponent {
|
|||
/>
|
||||
)}
|
||||
{!fileInfo && (
|
||||
<FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />
|
||||
<FilePrice
|
||||
uri={claim && claim.permanent_url ? claim.permanent_url : uri}
|
||||
style={filePageStyle.filePriceContainer}
|
||||
textStyle={filePageStyle.filePriceText}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TouchableOpacity style={filePageStyle.backButton} onPress={this.onBackButtonPressed}>
|
||||
|
|
|
@ -196,7 +196,7 @@ class PublishPage extends React.PureComponent {
|
|||
},
|
||||
() => {
|
||||
NativeModules.Gallery.getVideos().then(videos => this.setState({ videos, loadingVideos: false }));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Check if this is an edit action
|
||||
|
@ -288,7 +288,7 @@ class PublishPage extends React.PureComponent {
|
|||
this.handleChannelChange(channelName);
|
||||
}
|
||||
pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH_FORM);
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -356,18 +356,26 @@ class PublishPage extends React.PureComponent {
|
|||
}
|
||||
|
||||
if (!title || title.trim().length === 0) {
|
||||
notify({ message: __('Please provide a title') });
|
||||
notify({ message: __('Please provide a title'), isError: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
notify({ message: __('Please specify an address where people can find your content.') });
|
||||
notify({ message: __('Please specify an address where people can find your content.'), isError: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isNameValid(name, false)) {
|
||||
notify({ message: __('Your content address contains invalid characters.'), isError: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentMedia && !editMode) {
|
||||
// sanity check. normally shouldn't happen
|
||||
notify({ message: __('No file selected. Please select a video or take a photo before publishing.') });
|
||||
notify({
|
||||
message: __('No file selected. Please select a video or take a photo before publishing.'),
|
||||
isError: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -456,7 +464,7 @@ class PublishPage extends React.PureComponent {
|
|||
() => {
|
||||
this.handleNameChange(this.state.name);
|
||||
pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH_FORM);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -510,7 +518,7 @@ class PublishPage extends React.PureComponent {
|
|||
clearPublishFormState();
|
||||
// reset thumbnail
|
||||
updatePublishForm({ thumbnail: null });
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -537,7 +545,7 @@ class PublishPage extends React.PureComponent {
|
|||
},
|
||||
() => {
|
||||
NativeModules.UtilityModule.openDocumentPicker('*/*');
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -583,7 +591,7 @@ class PublishPage extends React.PureComponent {
|
|||
() => {
|
||||
// upload a new thumbnail
|
||||
uploadImageAsset(fileUrl, this.handleThumbnailUploadSuccess, this.handleThumbnailUploadFailure);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -634,7 +642,7 @@ class PublishPage extends React.PureComponent {
|
|||
videoRecordingMode: false,
|
||||
recordingVideo: false,
|
||||
},
|
||||
() => pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH_FORM)
|
||||
() => pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH_FORM),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -658,7 +666,7 @@ class PublishPage extends React.PureComponent {
|
|||
showCameraOverlay: false,
|
||||
videoRecordingMode: false,
|
||||
},
|
||||
() => pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH)
|
||||
() => pushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -777,8 +785,8 @@ class PublishPage extends React.PureComponent {
|
|||
uploadImageAsset(
|
||||
this.getFilePathFromUri(uri),
|
||||
this.handleThumbnailUploadSuccess,
|
||||
this.handleThumbnailUploadFailure
|
||||
)
|
||||
this.handleThumbnailUploadFailure,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if (mediaType === 'image' || mediaType === 'video') {
|
||||
|
@ -791,7 +799,7 @@ class PublishPage extends React.PureComponent {
|
|||
this.setState({ currentThumbnailUri: `file://${path}`, updatingThumbnailUri: false });
|
||||
if (!this.state.uploadedThumbnailUri) {
|
||||
this.setState({ uploadThumbnailStarted: true }, () =>
|
||||
uploadImageAsset(path, this.handleThumbnailUploadSuccess, this.handleThumbnailUploadFailure)
|
||||
uploadImageAsset(path, this.handleThumbnailUploadSuccess, this.handleThumbnailUploadFailure),
|
||||
);
|
||||
}
|
||||
})
|
||||
|
@ -817,7 +825,7 @@ class PublishPage extends React.PureComponent {
|
|||
},
|
||||
() => {
|
||||
this.handleNameChange(this.state.name);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -881,7 +889,7 @@ class PublishPage extends React.PureComponent {
|
|||
},
|
||||
() => {
|
||||
NativeModules.UtilityModule.openDocumentPicker('image/*');
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1112,7 +1120,7 @@ class PublishPage extends React.PureComponent {
|
|||
{__('The address where people can find your content (ex. lbry://myvideo). ')}
|
||||
{this.state.editMode &&
|
||||
__(
|
||||
'You cannot change this address while editing your content. If you wish to use a new address, please republish the content.'
|
||||
'You cannot change this address while editing your content. If you wish to use a new address, please republish the content.',
|
||||
)}
|
||||
</Text>
|
||||
|
||||
|
@ -1262,7 +1270,7 @@ class PublishPage extends React.PureComponent {
|
|||
</View>
|
||||
<Text style={publishStyle.successText}>
|
||||
{__(
|
||||
'Your content will be live in a few minutes. In the mean time, feel free to publish more content or explore the app.'
|
||||
'Your content will be live in a few minutes. In the mean time, feel free to publish more content or explore the app.',
|
||||
)}
|
||||
</Text>
|
||||
</View>
|
||||
|
|
|
@ -120,6 +120,22 @@ const fileListStyle = StyleSheet.create({
|
|||
marginLeft: 4,
|
||||
marginTop: 4,
|
||||
},
|
||||
filePriceContainer: {
|
||||
backgroundColor: Colors.NextLbryGreen,
|
||||
justifyContent: 'center',
|
||||
position: 'absolute',
|
||||
left: thumbnailWidth - 64,
|
||||
top: 8,
|
||||
width: 56,
|
||||
height: 24,
|
||||
borderRadius: 4,
|
||||
},
|
||||
filePriceText: {
|
||||
fontFamily: 'Inter-UI-Bold',
|
||||
fontSize: 12,
|
||||
textAlign: 'center',
|
||||
color: '#0c604b',
|
||||
},
|
||||
});
|
||||
|
||||
export default fileListStyle;
|
||||
|
|
|
@ -27,11 +27,16 @@ const walletStyle = StyleSheet.create({
|
|||
},
|
||||
address: {
|
||||
fontFamily: 'Inter-UI-Regular',
|
||||
letterSpacing: 0.8,
|
||||
borderWidth: 1,
|
||||
borderRadius: 16,
|
||||
borderStyle: 'dashed',
|
||||
borderColor: '#cccccc',
|
||||
borderColor: '#e1e1e1',
|
||||
backgroundColor: '#f9f9f9',
|
||||
padding: 8,
|
||||
paddingTop: 8,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
paddingBottom: 6,
|
||||
width: '85%',
|
||||
},
|
||||
button: {
|
||||
|
|
Loading…
Reference in a new issue