Misc tweaks and fixes ()

* channel icon auto thumbs. fix infinite claim list reload.
* tweak last page check
* additional tweaks and fixes before release
This commit is contained in:
Akinwale Ariwodola 2019-08-11 08:52:17 +01:00 committed by GitHub
parent 89222bc9ee
commit 38618080a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 212 additions and 119 deletions
src
component
AppNavigator.js
channelIconItem
claimList
fileItem
fileItemMedia
fileListItem
modalTagSelector
relatedContent
suggestedSubscriptionItem
constants.js
page
channel
downloads
file
search
subscriptions
styles

View file

@ -144,7 +144,7 @@ const drawer = createDrawerNavigator(
drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
MySubscriptionsStack: {
Subscriptions: {
screen: SubscriptionsPage,
navigationOptions: {
title: 'Subscriptions',
@ -270,21 +270,11 @@ class AppWithNavigationState extends React.Component {
'hardwareBackPress',
function() {
const { dispatch, nav, drawerStack } = this.props;
// There should be a better way to check this
if (nav.routes.length > 0) {
if (nav.routes[0].routeName === 'Main') {
const mainRoute = nav.routes[0];
if (
mainRoute.index > 0 ||
mainRoute.routes[0].index > 0 /* Discover stack index */ ||
mainRoute.routes[4].index > 0 /* Wallet stack index */ ||
mainRoute.index >= 5 /* Settings and About screens */
) {
if (drawerStack.length > 1) {
dispatchNavigateBack(dispatch, nav, drawerStack);
return true;
}
}
}
return false;
}.bind(this)
);

View file

@ -1,10 +1,17 @@
import { connect } from 'react-redux';
import { doResolveUri, makeSelectClaimForUri, makeSelectThumbnailForUri, makeSelectIsUriResolving } from 'lbry-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectThumbnailForUri,
makeSelectTitleForUri,
makeSelectIsUriResolving,
} from 'lbry-redux';
import ChannelIconItem from './view';
const select = (state, props) => ({
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
});

View file

@ -1,9 +1,35 @@
import React from 'react';
import { ActivityIndicator, Image, Text, TouchableOpacity, View } from 'react-native';
import Colors from 'styles/colors';
import autothumbStyle from 'styles/autothumb';
import channelIconStyle from 'styles/channelIcon';
export default class ChannelIconItem extends React.PureComponent {
static AUTO_THUMB_STYLES = [
autothumbStyle.autothumbPurple,
autothumbStyle.autothumbRed,
autothumbStyle.autothumbPink,
autothumbStyle.autothumbIndigo,
autothumbStyle.autothumbBlue,
autothumbStyle.autothumbLightBlue,
autothumbStyle.autothumbCyan,
autothumbStyle.autothumbTeal,
autothumbStyle.autothumbGreen,
autothumbStyle.autothumbYellow,
autothumbStyle.autothumbOrange,
];
state = {
autoStyle: null,
};
componentWillMount() {
this.setState({
autoStyle:
ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
});
}
componentDidMount() {
const { claim, isPlaceholder, uri, resolveUri } = this.props;
if (!claim && !isPlaceholder) {
@ -13,6 +39,8 @@ export default class ChannelIconItem extends React.PureComponent {
render() {
const { claim, isPlaceholder, isResolvingUri, onPress, thumbnail, title } = this.props;
const displayName = title || (claim ? claim.name : '');
const substrIndex = displayName.startsWith('@') ? 1 : 0;
return (
<TouchableOpacity style={channelIconStyle.container} onPress={onPress}>
@ -25,6 +53,7 @@ export default class ChannelIconItem extends React.PureComponent {
style={[
channelIconStyle.thumbnailContainer,
isPlaceholder ? channelIconStyle.borderedThumbnailContainer : null,
isPlaceholder ? null : this.state.autoStyle,
]}
>
{isPlaceholder && (
@ -32,17 +61,18 @@ export default class ChannelIconItem extends React.PureComponent {
<Text style={channelIconStyle.placeholderText}>ALL</Text>
</View>
)}
{!isPlaceholder && (
<Image
style={channelIconStyle.thumbnail}
resizeMode={'cover'}
source={thumbnail ? { uri: thumbnail } : require('../../assets/default_avatar.jpg')}
/>
{!isPlaceholder && thumbnail && (
<Image style={channelIconStyle.thumbnail} resizeMode={'cover'} source={{ uri: thumbnail }} />
)}
{!isPlaceholder && !thumbnail && (
<Text style={channelIconStyle.autothumbCharacter}>
{displayName.substring(substrIndex, substrIndex + 1).toUpperCase()}
</Text>
)}
</View>
{!isPlaceholder && (
<Text style={channelIconStyle.title} numberOfLines={1}>
{title || (claim ? claim.name : '')}
{displayName}
</Text>
)}
</TouchableOpacity>

View file

@ -22,6 +22,7 @@ class ClaimList extends React.PureComponent {
currentPage: 1, // initial page load is page 1
subscriptionsView: false, // whether or not this claim list is for subscriptions
trendingForAllView: false,
lastPageReached: false,
};
componentDidMount() {
@ -73,9 +74,10 @@ class ClaimList extends React.PureComponent {
channelIds: prevChannelIds,
trendingForAll: prevTrendingForAll,
time: prevTime,
claimSearchUris: prevClaimSearchUris,
showNsfwContent,
} = this.props;
const { orderBy, tags, channelIds, trendingForAll, time } = nextProps;
const { orderBy, tags, channelIds, trendingForAll, time, claimSearchUris } = nextProps;
if (
!_.isEqual(orderBy, prevOrderBy) ||
!_.isEqual(tags, prevTags) ||
@ -119,6 +121,18 @@ class ClaimList extends React.PureComponent {
}
});
}
if (
(this.state.subscriptionsView || this.state.trendingForAllView) &&
this.state.currentPage > 1 &&
prevClaimSearchUris &&
prevClaimSearchUris.length > 0 &&
_.isEqual(prevClaimSearchUris, claimSearchUris)
) {
this.setState({ lastPageReached: true });
} else {
this.setState({ lastPageReached: false });
}
}
getReleaseTimeOption = time => {
@ -130,6 +144,10 @@ class ClaimList extends React.PureComponent {
};
handleVerticalEndReached = () => {
if (this.state.lastPageReached) {
return;
}
// fetch more content
const {
channelIds,
@ -240,6 +258,17 @@ class ClaimList extends React.PureComponent {
if (Constants.ORIENTATION_VERTICAL === orientation) {
const data = subscriptionsView || trendingForAllView ? claimSearchUris : uris;
if (!loading && !claimSearchLoading && (!data || data.length === 0)) {
return (
<View style={style}>
<Text style={claimListStyle.noContentText}>
No content to display at this time. Please check back later.
</Text>
</View>
);
}
return (
<View style={style}>
<FlatList

View file

@ -8,6 +8,7 @@ import {
makeSelectTitleForUri,
makeSelectIsUriResolving,
makeSelectClaimIsNsfw,
makeSelectShortUrlForUri,
} from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings';
@ -20,6 +21,7 @@ const select = (state, props) => ({
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
shortUrl: makeSelectShortUrlForUri(props.uri)(state),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
nsfw: makeSelectClaimIsNsfw(props.uri)(state),

View file

@ -30,12 +30,12 @@ class FileItem extends React.PureComponent {
}
navigateToFileUri = () => {
const { navigation, uri } = this.props;
const { navigation, uri, shortUrl } = this.props;
const normalizedUri = normalizeURI(uri);
if (NativeModules.Firebase) {
NativeModules.Firebase.track('explore_click', { uri: normalizedUri });
NativeModules.Firebase.track('explore_click', { uri: normalizedUri, short_url: shortUrl });
}
navigateToUri(navigation, normalizedUri);
navigateToUri(navigation, shortUrl || uri);
};
render() {
@ -57,6 +57,11 @@ class FileItem extends React.PureComponent {
titleBeforeThumbnail,
} = this.props;
if (claim && claim.value_type === 'channel') {
// don't display channels in the lists on the Explore page
return null;
}
const uri = normalizeURI(this.props.uri);
const obscure = obscureNsfw && nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
@ -64,6 +69,7 @@ class FileItem extends React.PureComponent {
const channelName = signingChannel ? signingChannel.name : null;
const channelClaimId = signingChannel ? signingChannel.claim_id : null;
const fullChannelUri = channelClaimId ? `${channelName}#${channelClaimId}` : channelName;
const shortChannelUri = signingChannel ? signingChannel.short_url : null;
const height = claim ? claim.height : null;
return (
@ -104,7 +110,7 @@ class FileItem extends React.PureComponent {
style={discoverStyle.channelName}
text={channelName}
onPress={() => {
navigateToUri(navigation, normalizeURI(fullChannelUri));
navigateToUri(navigation, normalizeURI(shortChannelUri || fullChannelUri));
}}
/>
)}

View file

@ -2,24 +2,25 @@ import React from 'react';
import { ActivityIndicator, Image, Text, View } from 'react-native';
import Colors from 'styles/colors';
import FastImage from 'react-native-fast-image';
import autothumbStyle from 'styles/autothumb';
import fileItemMediaStyle from 'styles/fileItemMedia';
class FileItemMedia extends React.PureComponent {
static AUTO_THUMB_STYLES = [
fileItemMediaStyle.autothumbPurple,
fileItemMediaStyle.autothumbRed,
fileItemMediaStyle.autothumbPink,
fileItemMediaStyle.autothumbIndigo,
fileItemMediaStyle.autothumbBlue,
fileItemMediaStyle.autothumbLightBlue,
fileItemMediaStyle.autothumbCyan,
fileItemMediaStyle.autothumbTeal,
fileItemMediaStyle.autothumbGreen,
fileItemMediaStyle.autothumbYellow,
fileItemMediaStyle.autothumbOrange,
autothumbStyle.autothumbPurple,
autothumbStyle.autothumbRed,
autothumbStyle.autothumbPink,
autothumbStyle.autothumbIndigo,
autothumbStyle.autothumbBlue,
autothumbStyle.autothumbLightBlue,
autothumbStyle.autothumbCyan,
autothumbStyle.autothumbTeal,
autothumbStyle.autothumbGreen,
autothumbStyle.autothumbYellow,
autothumbStyle.autothumbOrange,
];
state: {
state = {
imageLoadFailed: false,
};
@ -48,7 +49,7 @@ class FileItemMedia extends React.PureComponent {
return false;
}
if (thumbnail.substring(0, 7) != 'http://' && thumbnail.substring(0, 8) != 'https://') {
if (thumbnail.substring(0, 7) !== 'http://' && thumbnail.substring(0, 8) !== 'https://') {
return false;
}
@ -67,12 +68,7 @@ class FileItemMedia extends React.PureComponent {
if (blurRadius > 0) {
// No blur radius support in FastImage yet
return (
<Image
source={{ uri: thumbnail }}
blurRadius={blurRadius}
resizeMode={resizeMode ? resizeMode : 'cover'}
style={style}
/>
<Image source={{ uri: thumbnail }} blurRadius={blurRadius} resizeMode={resizeMode || 'cover'} style={style} />
);
}
@ -87,7 +83,7 @@ class FileItemMedia extends React.PureComponent {
}
return (
<View style={[style ? style : fileItemMediaStyle.autothumb, atStyle]}>
<View style={[style || fileItemMediaStyle.autothumb, atStyle]}>
{isResolvingUri && (
<View style={fileItemMediaStyle.resolving}>
<ActivityIndicator color={Colors.White} size={'large'} />

View file

@ -6,6 +6,7 @@ import {
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
makeSelectClaimIsNsfw,
makeSelectShortUrlForUri,
makeSelectTitleForUri,
makeSelectThumbnailForUri,
} from 'lbry-redux';
@ -23,6 +24,7 @@ const select = (state, props) => ({
nsfw: makeSelectClaimIsNsfw(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
shortUrl: makeSelectShortUrlForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
});

View file

@ -42,8 +42,8 @@ class FileListItem extends React.PureComponent {
}
defaultOnPress = () => {
const { navigation, uri } = this.props;
navigateToUri(navigation, uri);
const { autoplay, navigation, uri, shortUrl } = this.props;
navigateToUri(navigation, shortUrl || uri, { autoplay });
};
render() {
@ -70,7 +70,7 @@ class FileListItem extends React.PureComponent {
const obscure = obscureNsfw && nsfw;
const isResolving = !fileInfo && isResolvingUri;
let name, channel, height, channelClaimId, fullChannelUri, shouldHide, signingChannel;
let name, channel, height, channelClaimId, fullChannelUri, shortChannelUri, shouldHide, signingChannel;
if (claim) {
name = claim.name;
signingChannel = claim.signing_channel;
@ -78,14 +78,18 @@ class FileListItem extends React.PureComponent {
height = claim.height;
channelClaimId = signingChannel ? signingChannel.claim_id : null;
fullChannelUri = channelClaimId ? `${channel}#${channelClaimId}` : channel;
shortChannelUri = signingChannel ? signingChannel.short_url : null;
if (blackListedOutpoints || filteredOutpoints) {
const outpointsToHide = blackListedOutpoints.concat(filteredOutpoints);
shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout);
}
// TODO: hide channels on tag pages?
// shouldHide = 'channel' === claim.value_type;
}
if (shouldHide || (featuredResult && !isResolvingUri && !claim && !title && !name)) {
if (shouldHide || (!isResolvingUri && !claim) || (featuredResult && !isResolvingUri && !claim && !title && !name)) {
return null;
}
@ -130,7 +134,7 @@ class FileListItem extends React.PureComponent {
style={fileListStyle.publisher}
text={channel}
onPress={() => {
navigateToUri(navigation, normalizeURI(fullChannelUri));
navigateToUri(navigation, normalizeURI(shortChannelUri || fullChannelUri));
}}
/>
)}

View file

@ -10,6 +10,8 @@ import TagSearch from 'component/tagSearch';
import modalTagSelectorStyle from 'styles/modalTagSelector';
import { __ } from 'utils/helper';
const minimumTags = 2;
export default class ModalTagSelector extends React.PureComponent {
handleAddTag = tag => {
if (!tag) {
@ -34,6 +36,12 @@ export default class ModalTagSelector extends React.PureComponent {
return;
}
const { followedTags, doToast } = this.props;
if (followedTags.length <= minimumTags) {
doToast({ message: __(`You can follow a minimum of ${minimumTags} tags.`) });
return;
}
this.props.doToggleTagFollow(tag);
if (window.persistor) {
window.persistor.flush();

View file

@ -57,7 +57,7 @@ export default class RelatedContent extends React.PureComponent {
key={recommendedUri}
uri={recommendedUri}
navigation={navigation}
onPress={() => navigateToUri(navigation, recommendedUri, { autoplay: true })}
autoplay
/>
))}
{isSearching && (

View file

@ -20,10 +20,13 @@ class SuggestedSubscriptionItem extends React.PureComponent {
render() {
const { claim, isResolvingUri, navigation, thumbnail, title, uri } = this.props;
let tags;
if (claim && claim.value) {
let shortUrl, tags;
if (claim) {
shortUrl = claim.short_url;
if (claim.value) {
tags = claim.value.tags;
}
}
if (isResolvingUri) {
return (
@ -54,7 +57,7 @@ class SuggestedSubscriptionItem extends React.PureComponent {
style={subscriptionsStyle.suggestedItemName}
numberOfLines={1}
text={claim.name}
onPress={() => navigateToUri(navigation, normalizeURI(uri))}
onPress={() => navigateToUri(navigation, normalizeURI(shortUrl || uri))}
/>
)}
{tags && (

View file

@ -79,7 +79,6 @@ const Constants = {
FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack',
FULL_ROUTE_NAME_TRENDING: 'TrendingStack',
FULL_ROUTE_NAME_MY_SUBSCRIPTIONS: 'MySubscriptionsStack',
FULL_ROUTE_NAME_WALLET: 'WalletStack',
ROUTE_FILE: 'File',

View file

@ -2,6 +2,7 @@
import React from 'react';
import { ActivityIndicator, Dimensions, Image, ScrollView, Text, TouchableOpacity, View } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';
import { normalizeURI } from 'lbry-redux';
import { navigateBack } from 'utils/helper';
import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
@ -164,8 +165,9 @@ class ChannelPage extends React.PureComponent {
const { fetching, claimsInChannel, claim, navigation, totalPages, uri, drawerStack, popDrawerStack } = this.props;
const { name, permanent_url: permanentUrl } = claim;
let thumbnailUrl, coverUrl, title;
if (claim && claim.value) {
let thumbnailUrl, coverUrl, title, fullUri;
if (claim) {
if (claim.value) {
title = claim.value.title;
if (claim.value.cover) {
coverUrl = claim.value.cover.url;
@ -175,6 +177,9 @@ class ChannelPage extends React.PureComponent {
}
}
fullUri = normalizeURI(`${claim.name}#${claim.claim_id}`);
}
return (
<View style={channelPageStyle.container}>
<UriBar value={uri} navigation={navigation} />
@ -208,10 +213,10 @@ class ChannelPage extends React.PureComponent {
</View>
<View style={channelPageStyle.subscribeButtonContainer}>
<SubscribeButton style={channelPageStyle.subscribeButton} uri={uri} name={name} />
<SubscribeButton style={channelPageStyle.subscribeButton} uri={fullUri} name={name} />
<SubscribeNotificationButton
style={[channelPageStyle.subscribeButton, channelPageStyle.bellButton]}
uri={uri}
uri={fullUri}
name={name}
/>
</View>

View file

@ -83,12 +83,7 @@ class DownloadsPage extends React.PureComponent {
style={downloadsStyle.scrollContainer}
contentContainerStyle={downloadsStyle.scrollPadding}
renderItem={({ item }) => (
<FileListItem
style={fileListStyle.item}
uri={item}
navigation={navigation}
onPress={() => navigateToUri(navigation, item, { autoplay: true })}
/>
<FileListItem style={fileListStyle.item} uri={item} navigation={navigation} autoplay />
)}
data={downloadedUris}
keyExtractor={(item, index) => item}

View file

@ -638,7 +638,10 @@ class FilePage extends React.PureComponent {
const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id;
const canSendTip = this.state.tipAmount > 0;
const fullChannelUri =
channelClaimId && channelClaimId.trim().length > 0 ? `${channelName}#${channelClaimId}` : channelName;
channelClaimId && channelClaimId.trim().length > 0
? normalizeURI(`${channelName}#${channelClaimId}`)
: normalizeURI(channelName);
const shortChannelUri = signingChannel ? signingChannel.short_url : null;
const playerStyle = [
filePageStyle.player,
@ -855,7 +858,7 @@ class FilePage extends React.PureComponent {
numberOfLines={1}
ellipsizeMode={'tail'}
onPress={() => {
navigateToUri(navigation, normalizeURI(fullChannelUri));
navigateToUri(navigation, normalizeURI(shortChannelUri || fullChannelUri));
}}
/>
)}

View file

@ -113,13 +113,7 @@ class SearchPage extends React.PureComponent {
)}
{uris && uris.length
? uris.map(uri => (
<FileListItem
key={uri}
uri={uri}
style={searchStyle.resultItem}
navigation={navigation}
onPress={() => navigateToUri(navigation, uri)}
/>
<FileListItem key={uri} uri={uri} style={searchStyle.resultItem} navigation={navigation} />
))
: null}
{(!uris || uris.length === 0) && (

View file

@ -74,7 +74,7 @@ class SubscriptionsPage extends React.PureComponent {
componentWillReceiveProps(nextProps) {
const { currentRoute } = nextProps;
const { currentRoute: prevRoute } = this.props;
if (Constants.FULL_ROUTE_NAME_MY_SUBSCRIPTIONS === currentRoute && currentRoute !== prevRoute) {
if (Constants.DRAWER_ROUTE_SUBSCRIPTIONS === currentRoute && currentRoute !== prevRoute) {
this.onComponentFocused();
}
}

39
src/styles/autothumb.js Normal file
View file

@ -0,0 +1,39 @@
import { StyleSheet } from 'react-native';
const autothumbStyle = StyleSheet.create({
autothumbPurple: {
backgroundColor: '#9c27b0',
},
autothumbRed: {
backgroundColor: '#e53935',
},
autothumbPink: {
backgroundColor: '#e91e63',
},
autothumbIndigo: {
backgroundColor: '#3f51b5',
},
autothumbBlue: {
backgroundColor: '#2196f3',
},
autothumbLightBlue: {
backgroundColor: '#039be5',
},
autothumbCyan: {
backgroundColor: '#00acc1',
},
autothumbTeal: {
backgroundColor: '#009688',
},
autothumbGreen: {
backgroundColor: '#43a047',
},
autothumbYellow: {
backgroundColor: '#ffeb3b',
},
autothumbOrange: {
backgroundColor: '#ffa726',
},
});
export default autothumbStyle;

View file

@ -18,6 +18,8 @@ const channelIconStyle = StyleSheet.create({
height: 80,
borderRadius: 160,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
},
borderedThumbnailContainer: {
borderWidth: 1,
@ -43,6 +45,11 @@ const channelIconStyle = StyleSheet.create({
marginTop: 4,
textAlign: 'center',
},
autothumbCharacter: {
fontFamily: 'Inter-UI-Regular',
fontSize: 48,
color: Colors.White,
},
});
export default channelIconStyle;

View file

@ -11,6 +11,13 @@ const claimListStyle = StyleSheet.create({
verticalScrollContainer: {
flex: 1,
},
noContentText: {
color: Colors.DescriptionGrey,
fontFamily: 'Inter-UI-Regular',
fontSize: 14,
margin: 16,
textAlign: 'center',
},
verticalScrollPadding: {
paddingBottom: 16,
},

View file

@ -80,7 +80,7 @@ const discoverStyle = StyleSheet.create({
marginTop: 12,
marginLeft: 16,
marginRight: 16,
marginBottom: 64,
marginBottom: 56,
},
footerTitle: {
fontFamily: 'Inter-UI-Regular',

View file

@ -15,39 +15,6 @@ const fileItemMediaStyle = StyleSheet.create({
color: Colors.White,
fontSize: 40,
},
autothumbPurple: {
backgroundColor: '#9c27b0',
},
autothumbRed: {
backgroundColor: '#e53935',
},
autothumbPink: {
backgroundColor: '#e91e63',
},
autothumbIndigo: {
backgroundColor: '#3f51b5',
},
autothumbBlue: {
backgroundColor: '#2196f3',
},
autothumbLightBlue: {
backgroundColor: '#039be5',
},
autothumbCyan: {
backgroundColor: '#00acc1',
},
autothumbTeal: {
backgroundColor: '#009688',
},
autothumbGreen: {
backgroundColor: '#43a047',
},
autothumbYellow: {
backgroundColor: '#ffeb3b',
},
autothumbOrange: {
backgroundColor: '#ffa726',
},
resolving: {
alignItems: 'center',
flex: 1,