diff --git a/src/component/fileDownloadButton/view.js b/src/component/fileDownloadButton/view.js
index cbb77b3..ee3f647 100644
--- a/src/component/fileDownloadButton/view.js
+++ b/src/component/fileDownloadButton/view.js
@@ -30,7 +30,6 @@ class FileDownloadButton extends React.PureComponent {
fileInfo,
downloading,
uri,
- purchaseUri,
costInfo,
isPlayable,
isViewable,
diff --git a/src/component/fileListItem/index.js b/src/component/fileListItem/index.js
index b9fb435..4f4e0e5 100644
--- a/src/component/fileListItem/index.js
+++ b/src/component/fileListItem/index.js
@@ -36,5 +36,5 @@ const perform = dispatch => ({
export default connect(
select,
- perform
+ perform,
)(FileListItem);
diff --git a/src/component/fileListItem/view.js b/src/component/fileListItem/view.js
index 32f87c0..c30abc5 100644
--- a/src/component/fileListItem/view.js
+++ b/src/component/fileListItem/view.js
@@ -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}
/>
)}
+
{featuredResult && (
diff --git a/src/component/uriBar/view.js b/src/component/uriBar/view.js
index 00426f1..86fbb60 100644
--- a/src/component/uriBar/view.js
+++ b/src/component/uriBar/view.js
@@ -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')}
diff --git a/src/component/walletSend/view.js b/src/component/walletSend/view.js
index a4036cf..61816e8 100644
--- a/src/component/walletSend/view.js
+++ b/src/component/walletSend/view.js
@@ -38,9 +38,10 @@ class WalletSend extends React.PureComponent {
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 {
if (amount > balance) {
notify({
message: __('Insufficient credits'),
+ isError: true,
});
return;
}
@@ -72,6 +74,7 @@ class WalletSend extends React.PureComponent {
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 {
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'}
diff --git a/src/page/file/view.js b/src/page/file/view.js
index 8e890a7..b34f19a 100644
--- a/src/page/file/view.js
+++ b/src/page/file/view.js
@@ -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 && (
-
+
)}
diff --git a/src/page/publish/view.js b/src/page/publish/view.js
index 6eed0a7..be48fd4 100644
--- a/src/page/publish/view.js
+++ b/src/page/publish/view.js
@@ -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.',
)}
@@ -1262,7 +1270,7 @@ class PublishPage extends React.PureComponent {
{__(
- '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.',
)}
diff --git a/src/styles/fileList.js b/src/styles/fileList.js
index 7c73e85..061b7bd 100644
--- a/src/styles/fileList.js
+++ b/src/styles/fileList.js
@@ -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;
diff --git a/src/styles/wallet.js b/src/styles/wallet.js
index c85bc79..e8df6f9 100644
--- a/src/styles/wallet.js
+++ b/src/styles/wallet.js
@@ -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: {