ongoing pre-beta tasks (#284)

* tapping on the player controls container while it is visible should hide the container
* change 'click' to 'tap'
* add related content component
* file list item resolving display tweaks
* increase number of search results to 25
* fix name display for identity claims in search results
This commit is contained in:
Akinwale Ariwodola 2018-09-05 14:43:39 +01:00 committed by GitHub
parent 05531e0bc5
commit 0638b9f133
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 228 additions and 58 deletions

9
app/package-lock.json generated
View file

@ -3990,8 +3990,8 @@
}
},
"lbryinc": {
"version": "github:lbryio/lbryinc#7910b565d7edda16be1c9d291f296982261ba60a",
"from": "github:lbryio/lbryinc#phone-verification",
"version": "github:lbryio/lbryinc#f2fff2a331578aef84eb77c108f976967afc50e0",
"from": "github:lbryio/lbryinc",
"requires": {
"lbry-redux": "github:lbryio/lbry-redux#31f7afa8a37f5741dac01fc1ecdf153f3bed95dc",
"reselect": "^3.0.0"
@ -5315,9 +5315,8 @@
}
},
"react-native-phone-input": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/react-native-phone-input/-/react-native-phone-input-0.2.1.tgz",
"integrity": "sha1-rGhSoeo32NWP+D3tUtGNe2MD5mc=",
"version": "github:lbryio/react-native-phone-input#60fdef484e8bf27328c7fb6a203baab9eb9cd4a1",
"from": "github:lbryio/react-native-phone-input",
"requires": {
"google-libphonenumber": "^2.0.9",
"lodash": "^4.17.4",

View file

@ -16,7 +16,7 @@
"react-native-fast-image": "^5.0.3",
"react-native-fetch-blob": "^0.10.8",
"react-native-image-zoom-viewer": "^2.2.5",
"react-native-phone-input": "^0.2.1",
"react-native-phone-input": "lbryio/react-native-phone-input",
"react-native-vector-icons": "^5.0.0",
"react-native-video": "lbryio/react-native-video#exoplayer-lbry-android",
"react-navigation": "^2.12.1",

View file

@ -5,8 +5,8 @@ import {
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
selectRewardContentClaimIds
} from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { selectShowNsfw } from '../../redux/selectors/settings';
import FileItem from './view';

View file

@ -3,8 +3,10 @@ import { normalizeURI } from 'lbry-redux';
import { NavigationActions } from 'react-navigation';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import { navigateToUri } from '../../utils/helper';
import Colors from '../../styles/colors';
import FileItemMedia from '../fileItemMedia';
import FilePrice from '../filePrice';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from '../link';
import NsfwOverlay from '../nsfwOverlay';
import discoverStyle from '../../styles/discover';
@ -65,7 +67,10 @@ class FileItem extends React.PureComponent {
isResolvingUri={isResolvingUri}
style={mediaStyle} />
<FilePrice uri={uri} style={discoverStyle.filePriceContainer} textStyle={discoverStyle.filePriceText} />
<Text style={discoverStyle.fileItemName}>{title}</Text>
<View style={isRewardContent ? discoverStyle.rewardTitleContainer : null}>
<Text style={[discoverStyle.fileItemName, discoverStyle.rewardTitle]}>{title}</Text>
{isRewardContent && <Icon style={discoverStyle.rewardIcon} name="award" size={20} />}
</View>
{channelName &&
<Link style={discoverStyle.channelName} text={channelName} onPress={() => {
const channelUri = normalizeURI(channelName);

View file

@ -8,7 +8,7 @@ import {
TouchableOpacity,
View
} from 'react-native';
import { navigateToUri } from '../../utils/helper';
import { navigateToUri, formatBytes } from '../../utils/helper';
import Colors from '../../styles/colors';
import FileItemMedia from '../fileItemMedia';
import Link from '../../component/link';
@ -18,27 +18,12 @@ import fileListStyle from '../../styles/fileList';
class FileListItem extends React.PureComponent {
getStorageForFileInfo = (fileInfo) => {
if (!fileInfo.completed) {
const written = this.formatBytes(fileInfo.written_bytes);
const total = this.formatBytes(fileInfo.total_bytes);
const written = formatBytes(fileInfo.written_bytes);
const total = formatBytes(fileInfo.total_bytes);
return `(${written} / ${total})`;
}
return this.formatBytes(fileInfo.written_bytes);
}
formatBytes = (bytes) => {
if (bytes < 1048576) { // < 1MB
const value = (bytes / 1024.0).toFixed(0);
return `${value} KB`;
}
if (bytes < 1073741824) { // < 1GB
const value = (bytes / (1024.0 * 1024.0)).toFixed(0);
return `${value} MB`;
}
const value = (bytes / (1024.0 * 1024.0 * 1024.0)).toFixed(0);
return `${value} GB`;
return formatBytes(fileInfo.written_bytes);
}
formatTitle = (title) => {
@ -90,19 +75,19 @@ class FileListItem extends React.PureComponent {
<FileItemMedia style={fileListStyle.thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
resizeMode="cover"
title={title}
title={(title || name)}
thumbnail={metadata ? metadata.thumbnail : null} />
<View style={fileListStyle.detailsContainer}>
{isResolving && (
{!title && !name && !channel && isResolving && (
<View>
<Text style={fileListStyle.uri}>{uri}</Text>
<View style={fileListStyle.row}>
{(!title && !name) && <Text style={fileListStyle.uri}>{uri}</Text>}
{(!title && !name) && <View style={fileListStyle.row}>
<ActivityIndicator size={"small"} color={Colors.LbryGreen} />
</View>
</View>}
</View>)}
{!isResolving && <Text style={fileListStyle.title}>{this.formatTitle(title) || this.formatTitle(name)}</Text>}
{!isResolving && channel &&
{(title || name) && <Text style={fileListStyle.title}>{this.formatTitle(title) || this.formatTitle(name)}</Text>}
{channel &&
<Link style={fileListStyle.publisher} text={channel} onPress={() => {
const channelUri = normalizeURI(channel);
navigateToUri(navigation, channelUri);

View file

@ -115,6 +115,11 @@ class MediaPlayer extends React.PureComponent {
this.hidePlayerControls();
}
manualHidePlayerControls = () => {
this.clearControlsTimeout();
this.setState({ areControlsVisible: false });
}
hidePlayerControls() {
const player = this;
let timeout = setTimeout(() => {
@ -123,6 +128,14 @@ class MediaPlayer extends React.PureComponent {
player.setState({ controlsTimeout: timeout });
}
togglePlayerControls = () => {
if (this.state.areControlsVisible) {
this.manualHidePlayerControls();
} else {
this.showPlayerControls();
}
}
togglePlay = () => {
this.showPlayerControls();
this.setState({ paused: !this.state.paused });
@ -342,7 +355,7 @@ class MediaPlayer extends React.PureComponent {
onEnd={this.onEnd}
/>
<TouchableOpacity style={mediaPlayerStyle.playerControls} onPress={this.showPlayerControls}>
<TouchableOpacity style={mediaPlayerStyle.playerControls} onPress={this.togglePlayerControls}>
{this.renderPlayerControls()}
</TouchableOpacity>

View file

@ -0,0 +1,23 @@
import { connect } from 'react-redux';
import {
makeSelectClaimForUri,
doSearch,
makeSelectRecommendedContentForUri,
selectIsSearching,
} from 'lbry-redux';
import RelatedContent from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
recommendedContent: makeSelectRecommendedContentForUri(props.uri)(state),
isSearching: selectIsSearching(state),
});
const perform = dispatch => ({
search: query => dispatch(doSearch(query, 10, undefined, true)),
});
export default connect(
select,
perform
)(RelatedContent);

View file

@ -0,0 +1,66 @@
import React from 'react';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';
import { navigateToUri } from '../../utils/helper';
import Colors from '../../styles/colors';
import FileListItem from '../fileListItem';
import fileListStyle from '../../styles/fileList';
import relatedContentStyle from '../../styles/relatedContent';
export default class RelatedContent extends React.PureComponent<Props> {
constructor() {
super();
this.didSearch = undefined;
}
componentDidMount() {
this.getRecommendedContent();
}
componentDidUpdate(prevProps: Props) {
const { claim, uri } = this.props;
if (uri !== prevProps.uri) {
this.didSearch = false;
}
if (claim && !this.didSearch) {
this.getRecommendedContent();
}
}
getRecommendedContent() {
const { claim, search } = this.props;
if (claim && claim.value && claim.value.stream && claim.value.stream.metadata) {
const { title } = claim.value.stream.metadata;
search(title);
this.didSearch = true;
}
}
didSearch: ?boolean;
render() {
const { recommendedContent, isSearching, navigation } = this.props;
if (!isSearching && (!recommendedContent || recommendedContent.length === 0)) {
return null;
}
return (
<View style={relatedContentStyle.container}>
<Text style={relatedContentStyle.title}>Related Content</Text>
{recommendedContent && recommendedContent.map(recommendedUri => (
<FileListItem
style={fileListStyle.item}
key={recommendedUri}
uri={recommendedUri}
navigation={navigation}
onPress={() => navigateToUri(navigation, recommendedUri, { autoplay: true })} />
))}
{isSearching && <ActivityIndicator size="small" color={Colors.LbryGreen} style={relatedContentStyle.loading} />}
</View>
);
}
}

View file

@ -5,6 +5,7 @@ import {
selectFeaturedUris,
selectFetchingFeaturedUris
} from 'lbry-redux';
import { doFetchRewardedContent } from 'lbryinc';
import DiscoverPage from './view';
const select = state => ({
@ -15,6 +16,7 @@ const select = state => ({
const perform = dispatch => ({
fetchFeaturedUris: () => dispatch(doFetchFeaturedUris()),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
});
export default connect(select, perform)(DiscoverPage);

View file

@ -41,7 +41,9 @@ class DiscoverPage extends React.PureComponent {
}
});
this.props.fetchFeaturedUris();
const { fetchFeaturedUris, fetchRewardedContent } = this.props;
fetchFeaturedUris();
fetchRewardedContent();
}
render() {

View file

@ -9,9 +9,9 @@ import {
makeSelectClaimForUri,
makeSelectContentTypeForUri,
makeSelectMetadataForUri,
selectRewardContentClaimIds,
selectBlackListedOutpoints,
selectBlackListedOutpoints,
} from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { doDeleteFile, doStopDownloadingFile } from '../../redux/actions/file';
import FilePage from './view';

View file

@ -15,6 +15,7 @@ import {
View,
WebView
} from 'react-native';
import { navigateToUri } from '../../utils/helper';
import ImageViewer from 'react-native-image-zoom-viewer';
import Button from '../../component/button';
import Colors from '../../styles/colors';
@ -25,6 +26,7 @@ import FilePrice from '../../component/filePrice';
import FloatingWalletBalance from '../../component/floatingWalletBalance';
import Link from '../../component/link';
import MediaPlayer from '../../component/mediaPlayer';
import RelatedContent from '../../component/relatedContent';
import UriBar from '../../component/uriBar';
import Video from 'react-native-video';
import filePageStyle from '../../styles/filePage';
@ -435,19 +437,23 @@ class FilePage extends React.PureComponent {
onPress={this.onStopDownloadPressed} />
}
</View>}
<ScrollView style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}>
<ScrollView
style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}
contentContainerstyle={showActions ? null : filePageStyle.scrollContent}>
<Text style={filePageStyle.title} selectable={true}>{title}</Text>
{channelName && <Link style={filePageStyle.channelName}
selectable={true}
text={channelName}
onPress={() => {
const channelUri = normalizeURI(channelName);
navigation.navigate({ routeName: 'File', key: 'filePage', params: { uri: channelUri }});
navigateToUri(navigation, channelUri);
}} />}
{description && description.length > 0 && <View style={filePageStyle.divider} />}
{description && <Text style={filePageStyle.description} selectable={true}>{this.linkify(description)}</Text>}
<RelatedContent navigation={navigation} uri={uri} />
</ScrollView>
</View>
)}

View file

@ -14,7 +14,7 @@ const select = (state) => ({
});
const perform = dispatch => ({
search: (query) => dispatch(doSearch(query))
search: (query) => dispatch(doSearch(query, 25))
});
export default connect(select, perform)(SearchPage);

View file

@ -2,6 +2,7 @@ import { connect } from 'react-redux';
import { doBalanceSubscribe, doNotify } from 'lbry-redux';
import {
doAuthenticate,
doFetchRewardedContent,
doUserEmailToVerify,
doUserEmailVerify,
doUserEmailVerifyFailure,
@ -18,8 +19,9 @@ const select = state => ({
const perform = dispatch => ({
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
notify: data => dispatch(doNotify(data)),
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
verifyUserEmail: (token, recaptcha) => dispatch(doUserEmailVerify(token, recaptcha)),

View file

@ -50,6 +50,8 @@ class SplashScreen extends React.PureComponent {
AsyncStorage.setItem('firstLaunchTime', String(moment().unix()));
}
});
this.props.fetchRewardedContent();
}
updateStatus() {
@ -109,7 +111,7 @@ class SplashScreen extends React.PureComponent {
});
}
} else {
navigation.navigate({ routeName: 'File', key: 'filePage', params: { uri: launchUrl } });
navigateToUri(navigation, launchUrl);
}
}
});

View file

@ -17,7 +17,7 @@ class WalletPage extends React.PureComponent {
<View>
<View style={walletStyle.warning}>
<Text style={walletStyle.warningText}>
This is beta software. You may lose any LBC that you send to your wallet due to uninstallation, software bugs, deleted files, or malicious third-party software. You should not use this wallet as your primary wallet. If you understand the risks and you wish to continue, please click the button below.
This is beta software. You may lose any LBC that you send to your wallet due to uninstallation, software bugs, deleted files, or malicious third-party software. You should not use this wallet as your primary wallet. If you understand the risks and you wish to continue, please tap the button below.
</Text>
</View>
<Button text={'I understand the risks'} style={[walletStyle.button, walletStyle.understand]}

View file

@ -15,6 +15,14 @@ import Constants from '../../constants';
const DOWNLOAD_POLL_INTERVAL = 250;
const deleteBlobsForSdHash = (sdHash) => {
Lbry.blob_list({ sd_hash: sdHash }).then(hashes => {
hashes.filter(hash => hash != sdHash).forEach(hash => {
Lbry.blob_delete({ blob_hash: hash });
});
});
};
export function doUpdateLoadStatus(uri, outpoint) {
return (dispatch, getState) => {
Lbry.file_list({
@ -44,10 +52,10 @@ export function doUpdateLoadStatus(uri, outpoint) {
}
// Once a download has been completed, delete the individual blob files to save space
Lbry.blob_list({ sd_hash: fileInfo.sd_hash }).then(hashes => {
hashes.filter(hash => hash != fileInfo.sd_hash).forEach(hash => {
Lbry.blob_delete({ blob_hash: hash });
});
Lbry.file_set_status({ status: 'stop', sd_hash: fileInfo.sd_hash }).then(() => {
deleteBlobsForSdHash(fileInfo.sd_hash);
}).catch(() => {
deleteBlobsForSdHash(fileInfo.sd_hash);
});
/*const notif = new window.Notification('LBRY Download Complete', {
@ -316,10 +324,10 @@ export function doDeleteCompleteBlobs() {
Lbry.file_list().then(files => {
files.forEach(fileInfo => {
if (fileInfo.completed) {
Lbry.blob_list({ sd_hash: fileInfo.sd_hash }).then(hashes => {
hashes.filter(hash => hash != fileInfo.sd_hash).forEach(hash => {
Lbry.blob_delete({ blob_hash: hash });
});
Lbry.file_set_status({ status: 'stop', sd_hash: fileInfo.sd_hash }).then(() => {
deleteBlobsForSdHash(fileInfo.sd_hash);
}).catch(() => {
deleteBlobsForSdHash(fileInfo.sd_hash);
});
}
});

View file

@ -107,10 +107,24 @@ const discoverStyle = StyleSheet.create({
height: '100%'
},
overlayText: {
color: '#ffffff',
color: Colors.White,
fontSize: 14,
textAlign: 'center',
fontFamily: 'Metropolis-Regular'
},
rewardTitleContainer: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between'
},
rewardIcon: {
color: Colors.LbryGreen,
flex: 0.1,
textAlign: 'right',
marginTop: 6
},
rewardTitle: {
flex: 0.9
}
});

View file

@ -43,8 +43,9 @@ const filePageStyle = StyleSheet.create({
},
scrollContainer: {
flex: 1,
marginTop: -16,
marginBottom: -4,
marginTop: -16
},
scrollContent: {
paddingTop: 10
},
scrollContainerActions: {
@ -73,7 +74,7 @@ const filePageStyle = StyleSheet.create({
lineHeight: 20,
marginLeft: 20,
marginRight: 20,
marginBottom: 40
marginBottom: 16
},
thumbnail: {
width: screenWidth,

View file

@ -0,0 +1,37 @@
import { StyleSheet } from 'react-native';
import Colors from './colors';
const relatedContentStyle = StyleSheet.create({
container: {
flex: 1,
paddingTop: 16,
paddingBottom: 16,
paddingLeft: 24,
paddingRight: 24,
borderTopColor: Colors.LighterGrey,
borderTopWidth: 1
},
title: {
fontFamily: 'Metropolis-Regular',
fontSize: 18,
},
itemList: {
flex: 1,
},
scrollContainer: {
flex: 1,
paddingLeft: 16,
paddingRight: 16,
marginTop: 16,
marginBottom: 60
},
scrollPadding: {
marginTop: -16,
paddingBottom: 16
},
loading: {
marginTop: 16
}
});
export default relatedContentStyle;

View file

@ -78,7 +78,6 @@ public class LbrynetService extends PythonService {
String serviceDescription = "The LBRY service is running in the background.";
Context context = getApplicationContext();
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -145,11 +144,17 @@ public class LbrynetService extends PythonService {
@Override
public void onDestroy() {
super.onDestroy();
if (stopServiceReceiver != null) {
unregisterReceiver(stopServiceReceiver);
stopServiceReceiver = null;
}
Context context = getApplicationContext();
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
super.onDestroy();
serviceInstance = null;
}