Fix release blockers #10

Merged
akinwale merged 7 commits from release-blockers into master 2019-08-10 08:55:13 +02:00
47 changed files with 405 additions and 241 deletions
package-lock.jsonpackage.json
src
component
AppNavigator.js
channelSelector
claimList
fileItem
fileListItem
modalTagSelector
subscribeNotificationButton
suggestedSubscriptionItem
tag
tagSearch
constants.js
page
about
channel
discover
downloads
file
firstRun
publish
publishes
rewards
search
settings
subscriptions
tag
transactionHistory
trending
verification
wallet
redux
styles
utils

8
package-lock.json generated
View file

@ -5562,8 +5562,8 @@
}
},
"lbry-redux": {
"version": "github:lbryio/lbry-redux#cd23c12fb7fd541d28d7cbf3874b1058b036fd13",
"from": "github:lbryio/lbry-redux#cd23c12fb7fd541d28d7cbf3874b1058b036fd13",
"version": "github:lbryio/lbry-redux#4e5e51b99b730cc834747edb9fd7d87d47a7d4f9",
"from": "github:lbryio/lbry-redux#4e5e51b99b730cc834747edb9fd7d87d47a7d4f9",
"requires": {
"proxy-polyfill": "0.1.6",
"reselect": "^3.0.0",
@ -5571,8 +5571,8 @@
}
},
"lbryinc": {
"version": "github:lbryio/lbryinc#2cc861145e79ed59478c150ac63f5ffc5fc2ad28",
"from": "github:lbryio/lbryinc",
"version": "github:lbryio/lbryinc#430c280789a5031c2e49ca5bf8a7d90ccccc4cdb",
"from": "github:lbryio/lbryinc#430c280789a5031c2e49ca5bf8a7d90ccccc4cdb",
"requires": {
"reselect": "^3.0.0"
}

View file

@ -12,8 +12,8 @@
"base-64": "^0.1.0",
"@expo/vector-icons": "^8.1.0",
"gfycat-style-urls": "^1.0.3",
"lbry-redux": "lbryio/lbry-redux#67a654f60630710cae72419448a73a18d076d18a",
"lbryinc": "lbryio/lbryinc",
"lbry-redux": "lbryio/lbry-redux#4e5e51b99b730cc834747edb9fd7d87d47a7d4f9",
"lbryinc": "lbryio/lbryinc#430c280789a5031c2e49ca5bf8a7d90ccccc4cdb",
"lodash": ">=4.17.11",
"merge": ">=1.2.1",
"moment": "^2.22.1",

View file

@ -127,79 +127,83 @@ const walletStack = createStackNavigator(
}
);
const drawerIconSize = 18;
const drawer = createDrawerNavigator(
{
DiscoverStack: {
screen: discoverStack,
navigationOptions: {
title: 'Explore',
drawerIcon: ({ tintColor }) => <Icon name="home" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="home" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
TrendingStack: {
screen: TrendingPage,
navigationOptions: {
title: 'Trending',
drawerIcon: ({ tintColor }) => <Icon name="fire" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
MySubscriptionsStack: {
screen: SubscriptionsPage,
navigationOptions: {
title: 'Subscriptions',
drawerIcon: ({ tintColor }) => <Icon name="heart" solid size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="heart" solid size={drawerIconSize} style={{ color: tintColor }} />,
},
},
WalletStack: {
screen: walletStack,
navigationOptions: {
title: 'Wallet',
drawerIcon: ({ tintColor }) => <Icon name="wallet" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="wallet" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
Publish: {
screen: PublishPage,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Icon name="upload" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="upload" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
Publishes: {
screen: PublishesPage,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Icon name="cloud-upload-alt" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => (
<Icon name="cloud-upload-alt" size={drawerIconSize} style={{ color: tintColor }} />
),
},
},
Rewards: {
screen: RewardsPage,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Icon name="award" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="award" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
MyLBRYStack: {
Downloads: {
screen: DownloadsPage,
navigationOptions: {
title: 'Library',
drawerIcon: ({ tintColor }) => <Icon name="download" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="download" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
Settings: {
screen: SettingsPage,
navigationOptions: {
drawerLockMode: 'locked-closed',
drawerIcon: ({ tintColor }) => <Icon name="cog" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="cog" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
About: {
screen: AboutPage,
navigationOptions: {
drawerLockMode: 'locked-closed',
drawerIcon: ({ tintColor }) => <Icon name="info" size={20} style={{ color: tintColor }} />,
drawerIcon: ({ tintColor }) => <Icon name="info" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
},
{
drawerWidth: 300,
headerMode: 'none',
backBehavior: 'none',
unmountInactiveRoutes: true,
contentComponent: DrawerContent,
contentOptions: {
@ -314,6 +318,7 @@ class AppWithNavigationState extends React.Component {
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
this.setState({ verifyPending: false });
NativeModules.Firebase.track('email_verified', { email: user.primary_email });
ToastAndroid.show('Your email address was successfully verified.', ToastAndroid.LONG);
// upon successful email verification, do wallet sync (if password has been set)

View file

@ -1,9 +1,9 @@
import React from 'react';
import { CLAIM_VALUES, isNameValid } from 'lbry-redux';
import { CLAIM_VALUES, isURIValid } from 'lbry-redux';
import { ActivityIndicator, Picker, Text, TextInput, TouchableOpacity, View } from 'react-native';
import Button from 'component/button';
import Colors from 'styles/colors';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import channelSelectorStyle from 'styles/channelSelector';
@ -102,7 +102,7 @@ export default class ChannelSelector extends React.PureComponent {
const { balance, createChannel, onChannelChange, notify } = this.props;
const { newChannelBid, newChannelName } = this.state;
if (newChannelName.trim().length === 0 || !isNameValid(newChannelName.substr(1), false)) {
if (newChannelName.trim().length === 0 || !isURIValid(newChannelName.substr(1), false)) {
notify({ message: 'Your channel name contains invalid characters.' });
return;
}

View file

@ -8,6 +8,7 @@ import {
selectFetchingClaimSearch,
selectLastClaimSearchUris,
} from 'lbry-redux';
import { selectShowNsfw } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import ClaimList from './view';
@ -18,6 +19,7 @@ const select = (state, props) => {
// for subscriptions
claimSearchLoading: selectFetchingClaimSearch(state),
claimSearchUris: selectLastClaimSearchUris(state),
showNsfwContent: selectShowNsfw(state),
};
};
@ -34,7 +36,6 @@ const perform = dispatch => ({
no_totals: true,
order_by: orderBy,
page,
not_tags: MATURE_TAGS,
},
additionalOptions
)

View file

@ -31,6 +31,7 @@ class ClaimList extends React.PureComponent {
claimSearch,
orderBy = Constants.DEFAULT_ORDER_BY,
searchByTags,
showNsfwContent,
tags,
time,
} = this.props;
@ -38,9 +39,11 @@ class ClaimList extends React.PureComponent {
const options = {
order_by: orderBy,
no_totals: true,
not_tags: MATURE_TAGS,
page: this.state.currentPage,
};
if (!showNsfwContent) {
options.not_tags = MATURE_TAGS;
}
if (channelIds) {
this.setState({ subscriptionsView: true });
options.channel_ids = channelIds;
@ -54,6 +57,9 @@ class ClaimList extends React.PureComponent {
if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
additionalOptions.release_time = this.getReleaseTimeOption(time);
}
if (!showNsfwContent) {
additionalOptions.not_tags = MATURE_TAGS;
}
searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
}
}
@ -67,6 +73,7 @@ class ClaimList extends React.PureComponent {
channelIds: prevChannelIds,
trendingForAll: prevTrendingForAll,
time: prevTime,
showNsfwContent,
} = this.props;
const { orderBy, tags, channelIds, trendingForAll, time } = nextProps;
if (
@ -85,9 +92,11 @@ class ClaimList extends React.PureComponent {
const options = {
order_by: orderBy,
no_totals: true,
not_tags: MATURE_TAGS,
page: this.state.currentPage,
};
if (!showNsfwContent) {
options.not_tags = MATURE_TAGS;
}
if (channelIds) {
this.setState({ subscriptionsView: true });
options.channel_ids = channelIds;
@ -103,6 +112,9 @@ class ClaimList extends React.PureComponent {
if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
additionalOptions.release_time = this.getReleaseTimeOption(time);
}
if (!showNsfwContent) {
additionalOptions.not_tags = MATURE_TAGS;
}
searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
}
});
@ -119,7 +131,17 @@ class ClaimList extends React.PureComponent {
handleVerticalEndReached = () => {
// fetch more content
const { channelIds, claimSearch, claimSearchUris, orderBy, searchByTags, tags, time, uris } = this.props;
const {
channelIds,
claimSearch,
claimSearchUris,
orderBy,
searchByTags,
showNsfwContent,
tags,
time,
uris,
} = this.props;
const { subscriptionsView, trendingForAllView } = this.state;
if ((claimSearchUris && claimSearchUris.length >= softLimit) || (uris && uris.length >= softLimit)) {
// don't fetch more than the specified limit to be displayed
@ -131,9 +153,11 @@ class ClaimList extends React.PureComponent {
const options = {
order_by: orderBy,
no_totals: true,
not_tags: MATURE_TAGS,
page: this.state.currentPage,
};
if (!showNsfwContent) {
options.not_tags = MATURE_TAGS;
}
if (subscriptionsView) {
options.channel_ids = channelIds;
}
@ -144,6 +168,9 @@ class ClaimList extends React.PureComponent {
if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
additionalOptions.release_time = this.getReleaseTimeOption(time);
}
if (!showNsfwContent) {
additionalOptions.not_tags = MATURE_TAGS;
}
searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
}
});
@ -174,6 +201,29 @@ class ClaimList extends React.PureComponent {
);
};
renderVerticalItem = ({ item }) => {
const { navigation } = this.props;
return <FileListItem key={item} uri={item} style={claimListStyle.verticalListItem} navigation={navigation} />;
};
renderHorizontalItem = ({ item }) => {
const { navigation } = this.props;
return item === Constants.MORE_PLACEHOLDER ? (
this.renderMorePlaceholder()
) : (
<FileItem
style={discoverStyle.fileItem}
mediaStyle={discoverStyle.fileItemMedia}
key={item}
uri={normalizeURI(item)}
navigation={navigation}
showDetails
compactView={false}
/>
);
};
render() {
const {
ListHeaderComponent,
@ -202,9 +252,7 @@ class ClaimList extends React.PureComponent {
initialNumToRender={10}
maxToRenderPerBatch={20}
removeClippedSubviews
renderItem={({ item }) => (
<FileListItem key={item} uri={item} style={claimListStyle.verticalListItem} navigation={navigation} />
)}
renderItem={this.renderVerticalItem}
data={data}
keyExtractor={(item, index) => item}
onEndReached={this.handleVerticalEndReached}
@ -235,21 +283,7 @@ class ClaimList extends React.PureComponent {
initialNumToRender={3}
maxToRenderPerBatch={3}
removeClippedSubviews
renderItem={({ item }) => {
return item === Constants.MORE_PLACEHOLDER ? (
this.renderMorePlaceholder()
) : (
<FileItem
style={discoverStyle.fileItem}
mediaStyle={discoverStyle.fileItemMedia}
key={item}
uri={normalizeURI(item)}
navigation={navigation}
showDetails
compactView={false}
/>
);
}}
renderItem={this.renderHorizontalItem}
horizontal
showsHorizontalScrollIndicator={false}
data={uris ? this.appendMorePlaceholder(uris.slice(0, horizontalLimit)) : []}

View file

@ -50,13 +50,15 @@ class FileItem extends React.PureComponent {
style,
mediaStyle,
navigation,
nsfw,
obscureNsfw,
showDetails,
compactView,
titleBeforeThumbnail,
} = this.props;
const uri = normalizeURI(this.props.uri);
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const obscure = obscureNsfw && nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
const signingChannel = claim ? claim.signing_channel : null;
const channelName = signingChannel ? signingChannel.name : null;
@ -75,7 +77,7 @@ class FileItem extends React.PureComponent {
<FileItemMedia
title={title}
thumbnail={thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
blurRadius={obscure ? 15 : 0}
resizeMode="cover"
isResolvingUri={isResolvingUri}
style={mediaStyle}
@ -106,13 +108,12 @@ class FileItem extends React.PureComponent {
}}
/>
)}
{!channelName && <Text style={discoverStyle.anonChannelName}>Anonymous</Text>}
<DateTime style={discoverStyle.dateTime} textStyle={discoverStyle.dateTimeText} timeAgo uri={uri} />
</View>
)}
</TouchableOpacity>
{obscureNsfw && (
<NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />
)}
{obscure && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
</View>
);
}

View file

@ -5,6 +5,7 @@ import {
makeSelectMetadataForUri,
makeSelectFileInfoForUri,
makeSelectIsUriResolving,
makeSelectClaimIsNsfw,
makeSelectTitleForUri,
makeSelectThumbnailForUri,
} from 'lbry-redux';
@ -19,6 +20,7 @@ const select = (state, props) => ({
filteredOutpoints: selectFilteredOutpoints(state),
isDownloaded: !!makeSelectFileInfoForUri(props.uri)(state),
metadata: makeSelectMetadataForUri(props.uri)(state),
nsfw: makeSelectClaimIsNsfw(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
title: makeSelectTitleForUri(props.uri)(state),

View file

@ -53,10 +53,12 @@ class FileListItem extends React.PureComponent {
fileInfo,
filteredOutpoints,
metadata,
nsfw,
featuredResult,
isResolvingUri,
isDownloaded,
style,
obscureNsfw,
onPress,
navigation,
thumbnail,
@ -65,7 +67,7 @@ class FileListItem extends React.PureComponent {
} = this.props;
const uri = normalizeURI(this.props.uri);
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const obscure = obscureNsfw && nsfw;
const isResolving = !fileInfo && isResolvingUri;
let name, channel, height, channelClaimId, fullChannelUri, shouldHide, signingChannel;
@ -92,7 +94,7 @@ class FileListItem extends React.PureComponent {
<TouchableOpacity style={style} onPress={onPress || this.defaultOnPress}>
<FileItemMedia
style={fileListStyle.thumbnail}
blurRadius={obscureNsfw ? 15 : 0}
blurRadius={obscure ? 15 : 0}
resizeMode="cover"
title={title || name}
thumbnail={thumbnail}
@ -155,9 +157,7 @@ class FileListItem extends React.PureComponent {
)}
</View>
</TouchableOpacity>
{obscureNsfw && (
<NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />
)}
{obscure && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
</View>
);
}

View file

@ -23,6 +23,9 @@ export default class ModalTagSelector extends React.PureComponent {
}
this.props.doToggleTagFollow(tag);
if (window.persistor) {
window.persistor.flush();
}
NativeModules.Firebase.track('tag_follow', { tag });
};
@ -32,6 +35,9 @@ export default class ModalTagSelector extends React.PureComponent {
}
this.props.doToggleTagFollow(tag);
if (window.persistor) {
window.persistor.flush();
}
NativeModules.Firebase.track('tag_unfollow', { tag });
};

View file

@ -5,17 +5,27 @@ import Button from 'component/button';
import Colors from 'styles/colors';
class SubscribeNotificationButton extends React.PureComponent {
render() {
handlePress = () => {
const {
uri,
name,
doChannelSubscriptionEnableNotifications,
doChannelSubscriptionDisableNotifications,
doToast,
enabledChannelNotifications,
isSubscribed,
style,
} = this.props;
const shouldNotify = enabledChannelNotifications.indexOf(name) > -1;
if (shouldNotify) {
doChannelSubscriptionDisableNotifications(name);
doToast({ message: 'You will not receive notifications for new content.' });
} else {
doChannelSubscriptionEnableNotifications(name);
doToast({ message: 'You will receive all notifications for new content.' });
}
};
render() {
const { enabledChannelNotifications, name, uri, isSubscribed, style } = this.props;
if (!isSubscribed) {
return null;
@ -31,23 +41,14 @@ class SubscribeNotificationButton extends React.PureComponent {
}
const shouldNotify = enabledChannelNotifications.indexOf(name) > -1;
const { claimName } = parseURI(uri);
return (
<Button
style={styles}
theme={'light'}
icon={shouldNotify ? 'bell-slash' : 'bell'}
solid={true}
onPress={() => {
if (shouldNotify) {
doChannelSubscriptionDisableNotifications(name);
doToast({ message: 'You will not receive notifications for new content.' });
} else {
doChannelSubscriptionEnableNotifications(name);
doToast({ message: 'You will receive all notifications for new content.' });
}
}}
solid
onPress={this.handlePress}
/>
);
}

View file

@ -1,11 +1,13 @@
import React from 'react';
import { buildURI, normalizeURI } from 'lbry-redux';
import { ActivityIndicator, FlatList, Image, Text, View } from 'react-native';
import { navigateToUri } from 'utils/helper';
import Colors from 'styles/colors';
import discoverStyle from 'styles/discover';
import FileItem from 'component/fileItem';
import SubscribeButton from 'component/subscribeButton';
import subscriptionsStyle from 'styles/subscriptions';
import Link from 'component/link';
import Tag from 'component/tag';
class SuggestedSubscriptionItem extends React.PureComponent {
@ -47,15 +49,22 @@ class SuggestedSubscriptionItem extends React.PureComponent {
{title}
</Text>
)}
<Text style={subscriptionsStyle.suggestedItemName} numberOfLines={1}>
{claim && claim.name}
</Text>
{claim && (
<Link
style={subscriptionsStyle.suggestedItemName}
numberOfLines={1}
text={claim.name}
onPress={() => navigateToUri(navigation, normalizeURI(uri))}
/>
)}
{tags && (
<View style={subscriptionsStyle.suggestedItemTagList}>
{tags &&
tags
.slice(0, 3)
.map(tag => <Tag style={subscriptionsStyle.tag} key={tag} name={tag} navigation={navigation} />)}
.map(tag => (
<Tag style={subscriptionsStyle.tag} key={tag} name={tag} navigation={navigation} truncate />
))}
</View>
)}
</View>

View file

@ -1,5 +1,6 @@
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { MATURE_TAGS } from 'lbry-redux';
import { formatTagName } from 'utils/helper';
import tagStyle from 'styles/tag';
import Colors from 'styles/colors';
@ -29,7 +30,7 @@ export default class Tag extends React.PureComponent {
};
render() {
const { name, onPress, style, type } = this.props;
const { name, onPress, style, type, truncate } = this.props;
let styles = [];
if (style) {
@ -41,7 +42,7 @@ export default class Tag extends React.PureComponent {
}
styles.push({
backgroundColor: Colors.TagGreen,
backgroundColor: MATURE_TAGS.includes(name) ? Colors.TagGrape : Colors.TagGreen,
borderRadius: 8,
marginBottom: 4,
});
@ -49,7 +50,7 @@ export default class Tag extends React.PureComponent {
return (
<TouchableOpacity style={styles} onPress={onPress || this.onPressDefault}>
<View style={tagStyle.content}>
<Text style={tagStyle.text}>{formatTagName(name)}</Text>
<Text style={tagStyle.text}>{truncate ? formatTagName(name) : name}</Text>
{type && <Icon style={tagStyle.icon} name={type === 'add' ? 'plus' : 'times'} size={8} />}
</View>
</TouchableOpacity>

View file

@ -1,5 +1,6 @@
import React from 'react';
import { KeyboardAvoidingView, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { MATURE_TAGS } from 'lbry-redux';
import Tag from 'component/tag';
import tagStyle from 'styles/tag';
import Colors from 'styles/colors';
@ -66,7 +67,7 @@ export default class TagSearch extends React.PureComponent {
};
render() {
const { name, style, type, selectedTags = [] } = this.props;
const { name, style, type, selectedTags = [], showNsfwTags } = this.props;
return (
<View>
@ -85,6 +86,22 @@ export default class TagSearch extends React.PureComponent {
))}
</View>
</KeyboardAvoidingView>
{showNsfwTags && (
<View style={tagStyle.nsfwTagsContainer}>
<Text style={tagStyle.nsfwTagsTitle}>Mature tags</Text>
<View style={tagStyle.tagResultsList}>
{MATURE_TAGS.map(tag => (
<Tag
key={tag}
name={tag}
style={tagStyle.tag}
type="add"
onAddPress={name => this.onAddTagPress(name)}
/>
))}
</View>
</View>
)}
</View>
);
}

View file

@ -53,6 +53,8 @@ const Constants = {
ACTION_REACT_NAVIGATION_NAVIGATE: 'Navigation/NAVIGATE',
ACTION_REACT_NAVIGATION_REPLACE: 'Navigation/REPLACE',
ACTION_SORT_BY_ITEM_CHANGED: 'SORT_BY_ITEM_CHANGED',
ORIENTATION_HORIZONTAL: 'horizontal',
ORIENTATION_VERTICAL: 'vertical',
@ -79,7 +81,6 @@ const Constants = {
FULL_ROUTE_NAME_TRENDING: 'TrendingStack',
FULL_ROUTE_NAME_MY_SUBSCRIPTIONS: 'MySubscriptionsStack',
FULL_ROUTE_NAME_WALLET: 'WalletStack',
FULL_ROUTE_NAME_MY_LBRY: 'MyLBRYStack',
ROUTE_FILE: 'File',

View file

@ -2,7 +2,7 @@ import React from 'react';
import { Lbry } from 'lbry-redux';
import { NativeModules, Text, View, ScrollView } from 'react-native';
import { navigateBack } from 'utils/helper';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Link from 'component/link';
import PageHeader from 'component/pageHeader';
import aboutStyle from 'styles/about';
@ -18,7 +18,7 @@ class AboutPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {
@ -105,7 +105,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.text}>Connected email</Text>
</View>
<View style={aboutStyle.col}>
<Text selectable={true} style={aboutStyle.valueText}>
<Text selectable style={aboutStyle.valueText}>
{userEmail}
</Text>
</View>
@ -125,7 +125,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.text}>App version</Text>
</View>
<View style={aboutStyle.col}>
<Text selectable={true} style={aboutStyle.valueText}>
<Text selectable style={aboutStyle.valueText}>
{this.state.appVersion}
</Text>
</View>
@ -136,7 +136,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.text}>Daemon (lbrynet)</Text>
</View>
<View style={aboutStyle.col}>
<Text selectable={true} style={aboutStyle.valueText}>
<Text selectable style={aboutStyle.valueText}>
{ver ? ver.lbrynet_version : loading}
</Text>
</View>
@ -147,7 +147,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.text}>Platform</Text>
</View>
<View style={aboutStyle.col}>
<Text selectable={true} style={aboutStyle.valueText}>
<Text selectable style={aboutStyle.valueText}>
{ver ? ver.platform : loading}
</Text>
</View>
@ -156,7 +156,7 @@ class AboutPage extends React.PureComponent {
<View style={aboutStyle.row}>
<View style={aboutStyle.col}>
<Text style={aboutStyle.text}>Installation ID</Text>
<Text selectable={true} style={aboutStyle.lineValueText}>
<Text selectable style={aboutStyle.lineValueText}>
{this.state.lbryId ? this.state.lbryId : loading}
</Text>
</View>

View file

@ -10,6 +10,7 @@ import Link from 'component/link';
import FileList from 'component/fileList';
import PageHeader from 'component/pageHeader';
import SubscribeButton from 'component/subscribeButton';
import SubscribeNotificationButton from 'component/subscribeNotificationButton';
import UriBar from 'component/uriBar';
import channelPageStyle from 'styles/channelPage';
@ -206,7 +207,14 @@ class ChannelPage extends React.PureComponent {
/>
</View>
<SubscribeButton style={channelPageStyle.subscribeButton} uri={uri} name={name} />
<View style={channelPageStyle.subscribeButtonContainer}>
<SubscribeButton style={channelPageStyle.subscribeButton} uri={uri} name={name} />
<SubscribeNotificationButton
style={[channelPageStyle.subscribeButton, channelPageStyle.bellButton]}
uri={uri}
name={name}
/>
</View>
</View>
<View style={channelPageStyle.tabBar}>

View file

@ -18,9 +18,8 @@ import {
selectSubscriptionClaims,
selectUnreadSubscriptions,
} from 'lbryinc';
import { doSetClientSetting } from 'redux/actions/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting, doSetSortByItem } from 'redux/actions/settings';
import { makeSelectClientSetting, selectSortByItem } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import DiscoverPage from './view';
@ -34,6 +33,7 @@ const select = state => ({
followedTags: selectFollowedTags(state),
ratingReminderDisabled: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_DISABLED)(state),
ratingReminderLastShown: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_LAST_SHOWN)(state),
sortByItem: selectSortByItem(state),
unreadSubscriptions: selectUnreadSubscriptions(state),
uris: selectLastClaimSearchUris(state),
});
@ -46,6 +46,7 @@ const perform = dispatch => ({
fileList: () => dispatch(doFileList()),
removeUnreadSubscriptions: () => dispatch(doRemoveUnreadSubscriptions()),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
setSortByItem: item => dispatch(doSetSortByItem(item)),
});
export default connect(

View file

@ -11,7 +11,7 @@ import {
View,
} from 'react-native';
import { DEFAULT_FOLLOWED_TAGS, Lbry, normalizeURI, parseURI } from 'lbry-redux';
import { __, formatTagTitle } from 'utils/helper';
import { __, formatTagTitle, getOrderBy } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage';
import moment from 'moment';
import CategoryList from 'component/categoryList';
@ -33,7 +33,6 @@ class DiscoverPage extends React.PureComponent {
showModalTagSelector: false,
showSortPicker: false,
orderBy: Constants.DEFAULT_ORDER_BY,
currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[0],
};
componentDidMount() {
@ -60,33 +59,22 @@ class DiscoverPage extends React.PureComponent {
}
});
const { fetchRewardedContent, fetchSubscriptions, fileList, followedTags } = this.props;
const { sortByItem, fetchRewardedContent, fetchSubscriptions, fileList, followedTags } = this.props;
this.buildTagCollection(followedTags);
fetchRewardedContent();
fetchSubscriptions();
fileList();
this.handleSortByItemSelected(sortByItem);
this.showRatingReminder();
}
handleSortByItemSelected = item => {
let orderBy = [];
switch (item.name) {
case Constants.SORT_BY_HOT:
orderBy = Constants.DEFAULT_ORDER_BY;
break;
case Constants.SORT_BY_NEW:
orderBy = ['release_time'];
break;
case Constants.SORT_BY_TOP:
orderBy = ['effective_amount'];
break;
}
this.setState({ currentSortByItem: item, orderBy, showSortPicker: false });
const { setSortByItem } = this.props;
setSortByItem(item);
const orderBy = getOrderBy(item);
this.setState({ orderBy, showSortPicker: false });
};
subscriptionForUri = (uri, channelName) => {
@ -217,7 +205,7 @@ class DiscoverPage extends React.PureComponent {
// each of the followed tags
const tagCollection = _.shuffle(tags)
.slice(0, 6)
.slice(0, 5)
.map(tag => [tag]);
// everything
tagCollection.unshift(tags);
@ -226,68 +214,77 @@ class DiscoverPage extends React.PureComponent {
};
handleTagPress = name => {
const { navigation } = this.props;
if (name.toLowerCase() !== 'trending') {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: `tagPage`, params: { tag: name } });
const { navigation, sortByItem } = this.props;
if (name.toLowerCase() !== 'all tags you follow') {
navigation.navigate({
routeName: Constants.DRAWER_ROUTE_TAG,
key: `tagPage`,
params: {
tag: name,
},
});
} else {
// navigate to the trending page
navigation.navigate({ routeName: Constants.FULL_ROUTE_NAME_TRENDING });
}
};
sectionListHeader = () => (
<View style={discoverStyle.titleRow}>
<Text style={discoverStyle.pageTitle}>Explore</Text>
<View style={discoverStyle.rightTitleRow}>
<Link
style={discoverStyle.customizeLink}
text={'Customize'}
onPress={() => this.setState({ showModalTagSelector: true })}
/>
<TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
<Text style={discoverStyle.tagSortText}>{this.props.sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
</View>
</View>
);
renderSectionListItem = ({ item, index, section }) => (
<ClaimList
key={item.sort().join(',')}
orderBy={this.state.orderBy}
time={Constants.TIME_WEEK}
tags={item}
morePlaceholder
navigation={this.props.navigation}
orientation={Constants.ORIENTATION_HORIZONTAL}
/>
);
renderSectionHeader = ({ section: { title } }) => (
<View style={discoverStyle.categoryTitleRow}>
<Text style={discoverStyle.categoryName} onPress={() => this.handleTagPress(title)}>
{formatTagTitle(title)}
</Text>
<TouchableOpacity onPress={() => this.handleTagPress(title)}>
<Icon name={'angle-double-down'} size={16} />
</TouchableOpacity>
</View>
);
render() {
const { navigation } = this.props;
const { currentSortByItem, orderBy, showModalTagSelector, showSortPicker } = this.state;
const { navigation, sortByItem } = this.props;
const { orderBy, showModalTagSelector, showSortPicker } = this.state;
return (
<View style={discoverStyle.container}>
<UriBar navigation={navigation} belowOverlay={showModalTagSelector} />
<SectionList
ListHeaderComponent={
<View style={discoverStyle.titleRow}>
<Text style={discoverStyle.pageTitle}>Explore</Text>
<View style={discoverStyle.rightTitleRow}>
<Link
style={discoverStyle.customizeLink}
text={'Customize'}
onPress={() => this.setState({ showModalTagSelector: true })}
/>
<TouchableOpacity
style={discoverStyle.tagSortBy}
onPress={() => this.setState({ showSortPicker: true })}
>
<Text style={discoverStyle.tagSortText}>{currentSortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
</View>
</View>
}
ListHeaderComponent={this.sectionListHeader}
style={discoverStyle.scrollContainer}
contentContainerStyle={discoverStyle.scrollPadding}
initialNumToRender={4}
maxToRenderPerBatch={4}
removeClippedSubviews
renderItem={({ item, index, section }) => (
<ClaimList
key={item.sort().join(',')}
orderBy={orderBy}
time={Constants.TIME_WEEK}
tags={item}
morePlaceholder
navigation={navigation}
orientation={Constants.ORIENTATION_HORIZONTAL}
/>
)}
renderSectionHeader={({ section: { title } }) => (
<View style={discoverStyle.categoryTitleRow}>
<Text style={discoverStyle.categoryName} onPress={() => this.handleTagPress(title)}>
{formatTagTitle(title)}
</Text>
<TouchableOpacity onPress={() => this.handleTagPress(title)}>
<Icon name={'angle-double-down'} size={16} />
</TouchableOpacity>
</View>
)}
renderItem={this.renderSectionListItem}
renderSectionHeader={this.renderSectionHeader}
sections={this.buildSections()}
keyExtractor={(item, index) => item}
/>
@ -303,7 +300,7 @@ class DiscoverPage extends React.PureComponent {
title={__('Sort content by')}
onOverlayPress={() => this.setState({ showSortPicker: false })}
onItemSelected={this.handleSortByItemSelected}
selectedItem={currentSortByItem}
selectedItem={sortByItem}
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/>
)}

View file

@ -21,7 +21,7 @@ class DownloadsPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {
@ -44,7 +44,7 @@ class DownloadsPage extends React.PureComponent {
componentWillReceiveProps(nextProps) {
const { currentRoute } = nextProps;
const { currentRoute: prevRoute } = this.props;
if (Constants.FULL_ROUTE_NAME_MY_LBRY === currentRoute && currentRoute !== prevRoute) {
if (Constants.DRAWER_ROUTE_MY_LBRY === currentRoute && currentRoute !== prevRoute) {
this.onComponentFocused();
}
}

View file

@ -88,7 +88,7 @@ class FilePage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
onComponentFocused = () => {
@ -913,6 +913,7 @@ class FilePage extends React.PureComponent {
<TextInput
ref={ref => (this.tipAmountInput = ref)}
onChangeText={value => this.setState({ tipAmount: value })}
underlineColorAndroid={Colors.NextLbryGreen}
keyboardType={'numeric'}
placeholder={'0'}
value={this.state.tipAmount}

View file

@ -4,7 +4,7 @@ import { ActivityIndicator, Linking, NativeModules, Text, TouchableOpacity, View
import { NavigationActions, StackActions } from 'react-navigation';
import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import WalletPage from './internal/wallet-page';
import WelcomePage from './internal/welcome-page';
import EmailCollectPage from './internal/email-collect-page';
@ -73,6 +73,7 @@ class FirstRunScreen extends React.PureComponent {
notify({ message: String(emailNewErrorMessage), isError: true });
} else {
// Request successful. Navigate to email verify page.
NativeModules.Firebase.track('email_added', { email: this.state.email });
this.showPage(Constants.FIRST_RUN_PAGE_EMAIL_VERIFY);
}
}
@ -228,7 +229,7 @@ class FirstRunScreen extends React.PureComponent {
onEmailChanged = email => {
this.setState({ email });
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT == this.state.currentPage) {
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT === this.state.currentPage) {
this.setState({ showSkip: !email || email.trim().length === 0 });
} else {
this.setState({ showSkip: false });
@ -236,14 +237,14 @@ class FirstRunScreen extends React.PureComponent {
};
onEmailViewLayout = phase => {
if ('collect' === phase) {
if (phase === 'collect') {
if (!this.state.emailCollectTracked) {
// we only want to track this once
this.setState({ emailCollectTracked: true }, () =>
NativeModules.Firebase.track('first_run_email_collect', null)
);
}
} else if ('verify' === phase) {
} else if (phase === 'verify') {
NativeModules.Firebase.track('first_run_email_verify', null);
}
@ -402,10 +403,10 @@ class FirstRunScreen extends React.PureComponent {
{Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT !== this.state.currentPage &&
Constants.FIRST_RUN_PAGE_EMAIL_VERIFY !== this.state.currentPage && (
<Text style={firstRunStyle.buttonText}>
{Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage ? 'Use LBRY' : 'Continue'} »
</Text>
)}
<Text style={firstRunStyle.buttonText}>
{Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage ? 'Use LBRY' : 'Continue'} »
</Text>
)}
</TouchableOpacity>
)}
</View>

View file

@ -15,7 +15,15 @@ import {
View,
} from 'react-native';
import { FlatGrid } from 'react-native-super-grid';
import { isNameValid, buildURI, regexInvalidURI, CLAIM_VALUES, LICENSES, THUMBNAIL_STATUSES } from 'lbry-redux';
import {
isNameValid,
buildURI,
regexInvalidURI,
CLAIM_VALUES,
LICENSES,
MATURE_TAGS,
THUMBNAIL_STATUSES,
} from 'lbry-redux';
import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker';
import { RNCamera } from 'react-native-camera';
import { generateCombination } from 'gfycat-style-urls';
@ -116,7 +124,7 @@ class PublishPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
DeviceEventEmitter.addListener('onGalleryThumbnailsChecked', this.handleGalleryThumbnailsChecked);
}
@ -203,10 +211,6 @@ class PublishPage extends React.PureComponent {
}
const publishTags = tags.slice();
if (mature) {
publishTags.push('nsfw');
}
const publishParams = {
filePath: currentMedia.filePath,
bid: bid || 0.1,
@ -215,7 +219,7 @@ class PublishPage extends React.PureComponent {
thumbnail: thumbnail,
description: description || '',
language,
nsfw: mature,
nsfw: publishTags.some(tag => MATURE_TAGS.includes(tag)),
license,
licenseUrl: '',
otherLicenseDescription: '',
@ -654,7 +658,7 @@ class PublishPage extends React.PureComponent {
/>
))}
</View>
<TagSearch handleAddTag={this.handleAddTag} selectedTags={this.state.tags} />
<TagSearch handleAddTag={this.handleAddTag} selectedTags={this.state.tags} showNsfwTags />
</View>
<View style={publishStyle.card}>
@ -727,11 +731,6 @@ class PublishPage extends React.PureComponent {
{this.state.advancedMode && (
<View style={publishStyle.card}>
<Text style={publishStyle.cardTitle}>Additional Options</Text>
<View style={publishStyle.toggleField}>
<Switch value={this.state.mature} onValueChange={value => this.setState({ mature: value })} />
<Text style={publishStyle.toggleText}>Mature content</Text>
</View>
<View>
<Text style={publishStyle.cardText}>Language</Text>
<Picker

View file

@ -14,7 +14,7 @@ class PublishesPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {
@ -23,6 +23,10 @@ class PublishesPage extends React.PureComponent {
}
}
componentDidMount() {
this.onComponentFocused();
}
onComponentFocused = () => {
const { checkPendingPublishes, pushDrawerStack, setPlayerVisible } = this.props;

View file

@ -28,7 +28,7 @@ class RewardsPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -24,7 +24,7 @@ class SearchPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -2,7 +2,7 @@ import React from 'react';
import { SETTINGS } from 'lbry-redux';
import { Text, View, ScrollView, Switch, NativeModules } from 'react-native';
import { navigateBack } from 'utils/helper';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import PageHeader from 'component/pageHeader';
import settingsStyle from 'styles/settings';
@ -15,7 +15,7 @@ class SettingsPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -42,7 +42,7 @@ class SubscriptionsPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -1,16 +1,19 @@
import { connect } from 'react-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetSortByItem } from 'redux/actions/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer';
import Constants from 'constants';
import { selectSortByItem } from 'redux/selectors/settings';
import TagPage from './view';
const select = state => ({
currentRoute: selectCurrentRoute(state),
sortByItem: selectSortByItem(state),
});
const perform = dispatch => ({
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_TAG)),
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setSortByItem: item => dispatch(doSetSortByItem(item)),
});
export default connect(

View file

@ -1,7 +1,7 @@
import React from 'react';
import { ActivityIndicator, NativeModules, FlatList, Text, TouchableOpacity, View } from 'react-native';
import { DEFAULT_FOLLOWED_TAGS, normalizeURI } from 'lbry-redux';
import { formatTagTitle } from 'utils/helper';
import { formatTagTitle, getOrderBy } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage';
import moment from 'moment';
import ClaimList from 'component/claimList';
@ -22,7 +22,6 @@ class TagPage extends React.PureComponent {
showTimePicker: false,
orderBy: Constants.DEFAULT_ORDER_BY,
time: Constants.TIME_WEEK,
currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[0],
currentTimeItem: Constants.CLAIM_SEARCH_TIME_ITEMS[1],
};
@ -30,7 +29,7 @@ class TagPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {
@ -40,9 +39,10 @@ class TagPage extends React.PureComponent {
}
onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible, navigation } = this.props;
this.setState({ tag: navigation.state.params.tag });
pushDrawerStack();
const { navigation, pushDrawerStack, setPlayerVisible, sortByItem } = this.props;
const { tag } = navigation.state.params;
this.setState({ tag, sortByItem, orderBy: getOrderBy(sortByItem) });
pushDrawerStack(Constants.DRAWER_ROUTE_TAG, navigation.state.params);
setPlayerVisible();
};
@ -59,22 +59,9 @@ class TagPage extends React.PureComponent {
}
handleSortByItemSelected = item => {
let orderBy = [];
switch (item.name) {
case Constants.SORT_BY_HOT:
orderBy = Constants.DEFAULT_ORDER_BY;
break;
case Constants.SORT_BY_NEW:
orderBy = ['release_time'];
break;
case Constants.SORT_BY_TOP:
orderBy = [Constants.ORDER_BY_EFFECTIVE_AMOUNT];
break;
}
this.setState({ currentSortByItem: item, orderBy, showSortPicker: false });
const { setSortByItem } = this.props;
setSortByItem(item);
this.setState({ orderBy: getOrderBy(item), showSortPicker: false });
};
handleTimeItemSelected = item => {
@ -82,8 +69,8 @@ class TagPage extends React.PureComponent {
};
render() {
const { navigation } = this.props;
const { tag, currentSortByItem, currentTimeItem, showSortPicker, showTimePicker } = this.state;
const { navigation, sortByItem } = this.props;
const { tag, currentTimeItem, showSortPicker, showTimePicker } = this.state;
return (
<View style={discoverStyle.container}>
@ -92,14 +79,14 @@ class TagPage extends React.PureComponent {
ListHeaderComponent={
<View style={discoverStyle.tagTitleRow}>
<Text style={discoverStyle.tagPageTitle}>{formatTagTitle(tag)}</Text>
{Constants.SORT_BY_TOP === currentSortByItem.name && (
{Constants.SORT_BY_TOP === sortByItem.name && (
<TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
<Text style={discoverStyle.tagSortText}>{currentTimeItem.label}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
<TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
<Text style={discoverStyle.tagSortText}>{currentSortByItem.label.split(' ')[0]}</Text>
<Text style={discoverStyle.tagSortText}>{sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
</View>
@ -117,7 +104,7 @@ class TagPage extends React.PureComponent {
title={__('Sort content by')}
onOverlayPress={() => this.setState({ showSortPicker: false })}
onItemSelected={this.handleSortByItemSelected}
selectedItem={this.state.currentSortByItem}
selectedItem={this.state.sortByItem}
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/>
)}

View file

@ -1,6 +1,6 @@
import React from 'react';
import { View, ScrollView, Text } from 'react-native';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import TransactionList from 'component/transactionList';
import UriBar from 'component/uriBar';
import walletStyle from 'styles/wallet';
@ -10,7 +10,7 @@ class TransactionHistoryPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -31,7 +31,7 @@ class TrendingPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -1,11 +1,11 @@
import React from 'react';
import { Lbry } from 'lbry-redux';
import { ActivityIndicator, View, Text, TextInput } from 'react-native';
import { ActivityIndicator, NativeModules, View, Text, TextInput } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import Button from 'component/button';
import Link from 'component/link';
import Colors from 'styles/colors';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import firstRunStyle from 'styles/firstRun';
import rewardStyle from 'styles/reward';
@ -44,11 +44,12 @@ class EmailVerifyPage extends React.PureComponent {
notify({ message: String(emailNewErrorMessage), isError: true });
this.setState({ verifyStarted: false });
} else {
NativeModules.Firebase.track('email_added', { email: this.state.email });
this.setState({ phase: Constants.PHASE_VERIFICATION });
if (setEmailVerificationPhase) {
setEmailVerificationPhase(true);
}
//notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
// notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
}
}

View file

@ -4,7 +4,7 @@ import { ActivityIndicator, Linking, NativeModules, Text, TouchableOpacity, View
import { NavigationActions, StackActions } from 'react-navigation';
import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import EmailVerifyPage from './internal/email-verify-page';
import ManualVerifyPage from './internal/manual-verify-page';
import PhoneVerifyPage from './internal/phone-verify-page';
@ -68,6 +68,9 @@ class VerificationScreen extends React.PureComponent {
if (this.state.isEmailVerified && this.state.isRewardApproved) {
// verification steps already completed
// simply navigate back to the rewards page
if (user.primary_email) {
NativeModules.Firebase.track('reward_eligibility_completed', { email: user.primary_email });
}
navigation.goBack();
}
}

View file

@ -9,7 +9,7 @@ import WalletSyncDriver from 'component/walletSyncDriver';
import Button from 'component/button';
import Link from 'component/link';
import UriBar from 'component/uriBar';
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import walletStyle from 'styles/wallet';
class WalletPage extends React.PureComponent {
@ -17,7 +17,7 @@ class WalletPage extends React.PureComponent {
componentWillMount() {
const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
}
componentWillUnmount() {

View file

@ -1,9 +1,9 @@
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
export const doPushDrawerStack = routeName => dispatch =>
export const doPushDrawerStack = (routeName, params) => dispatch =>
dispatch({
type: Constants.ACTION_PUSH_DRAWER_STACK,
data: routeName,
data: { routeName, params },
});
export const doPopDrawerStack = () => dispatch =>

View file

@ -1,4 +1,5 @@
import { ACTIONS } from 'lbry-redux';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
export function doSetClientSetting(key, value) {
return dispatch => {
@ -15,3 +16,14 @@ export function doSetClientSetting(key, value) {
}
};
}
export function doSetSortByItem(item) {
return dispatch => {
dispatch({
type: Constants.ACTION_SORT_BY_ITEM_CHANGED,
data: {
name: item.name,
},
});
};
}

View file

@ -1,8 +1,8 @@
import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
const reducers = {};
const defaultState = {
stack: [Constants.DRAWER_ROUTE_DISCOVER], // Discover is always the first drawer route
stack: [{ route: Constants.DRAWER_ROUTE_DISCOVER, params: {} }], // Discover is always the first drawer route
playerVisible: false,
currentRoute: null,
};
@ -13,11 +13,11 @@ reducers[Constants.ACTION_SET_PLAYER_VISIBLE] = (state, action) =>
});
reducers[Constants.ACTION_PUSH_DRAWER_STACK] = (state, action) => {
const routeName = action.data;
const { routeName, params } = action.data;
const newStack = state.stack.slice();
if (routeName !== newStack[newStack.length - 1]) {
newStack.push(routeName);
if (routeName !== newStack[newStack.length - 1].route) {
newStack.push({ route: routeName, params });
}
return {

View file

@ -1,8 +1,10 @@
import { ACTIONS } from 'lbry-redux';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
const reducers = {};
const defaultState = {
clientSettings: {},
sortByItemName: Constants.SORT_BY_HOT,
};
reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
@ -16,6 +18,11 @@ reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
});
};
reducers[Constants.ACTION_SORT_BY_ITEM_CHANGED] = (state, action) =>
Object.assign({}, state, {
sortByItemName: action.data.name,
});
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);

View file

@ -1,5 +1,6 @@
import { SETTINGS } from 'lbry-redux';
import { createSelector } from 'reselect';
import { getSortByItemForName } from 'utils/helper';
const selectState = state => state.settings || {};
@ -13,6 +14,11 @@ export const selectClientSettings = createSelector(
state => state.clientSettings || {}
);
export const selectSortByItem = createSelector(
selectState,
state => getSortByItemForName(state.sortByItemName)
);
export const makeSelectClientSetting = setting =>
createSelector(
selectClientSettings,

View file

@ -66,15 +66,21 @@ const channelPageStyle = StyleSheet.create({
fontFamily: 'Inter-UI-Regular',
fontSize: 18,
},
subscribeButtonContainer: {
position: 'absolute',
flexDirection: 'row',
left: 8,
bottom: -90,
zIndex: 100,
},
subscribeButton: {
alignSelf: 'flex-start',
backgroundColor: Colors.White,
paddingLeft: 16,
paddingRight: 16,
position: 'absolute',
right: 8,
bottom: -88,
zIndex: 100,
},
bellButton: {
marginLeft: 8,
},
cover: {
width: '100%',
@ -120,6 +126,7 @@ const channelPageStyle = StyleSheet.create({
marginBottom: 24,
},
aboutScrollContent: {
paddingTop: 52,
padding: 24,
},
aboutTitle: {

View file

@ -10,6 +10,7 @@ const Colors = {
BrighterLbryGreen: '#40b887',
NextLbryGreen: '#38d9a9',
TagGreen: '#e3f6f1',
TagGrape: '#da77f255',
LightGrey: '#cccccc',
LighterGrey: '#e5e5e5',
Orange: '#ffbb00',

View file

@ -121,6 +121,12 @@ const discoverStyle = StyleSheet.create({
marginTop: 4,
color: Colors.LbryGreen,
},
anonChannelName: {
fontFamily: 'Inter-UI-SemiBold',
fontSize: 12,
marginTop: 4,
color: Colors.DescriptionGrey,
},
downloadedIcon: {
position: 'absolute',
right: 8,

View file

@ -289,6 +289,7 @@ const filePageStyle = StyleSheet.create({
},
tipAmountInput: {
alignSelf: 'flex-start',
textAlign: 'right',
width: 80,
fontSize: 16,
letterSpacing: 1,

View file

@ -114,6 +114,7 @@ const publishStyle = StyleSheet.create({
width: 80,
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
textAlign: 'right',
},
currency: {
fontFamily: 'Inter-UI-Regular',

View file

@ -30,6 +30,14 @@ const tagStyle = StyleSheet.create({
flexDirection: 'row',
flexWrap: 'wrap',
},
nsfwTagsContainer: {
marginTop: 8,
},
nsfwTagsTitle: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
marginBottom: 4,
},
});
export default tagStyle;

View file

@ -154,11 +154,12 @@ export function navigateBack(navigation, drawerStack, popDrawerStack) {
}
const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route, params } = target;
navigation.goBack(navigation.state.key);
if (DrawerRoutes.indexOf(target) === -1 && isURIValid(target)) {
navigateToUri(navigation, target, null, true);
if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
navigateToUri(navigation, route, null, true);
} else {
navigation.navigate({ routeName: target });
navigation.navigate({ routeName: route, params });
}
}
@ -166,13 +167,15 @@ export function dispatchNavigateBack(dispatch, nav, drawerStack) {
dispatch(doPopDrawerStack());
const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route } = target;
dispatch(NavigationActions.back());
if (DrawerRoutes.indexOf(target) === -1 && isURIValid(target)) {
dispatchNavigateToUri(dispatch, nav, target, true);
if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
dispatchNavigateToUri(dispatch, nav, route, true);
} else {
const newTarget = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const navigateAction = NavigationActions.navigate({
routeName: drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0],
routeName: newTarget.route,
params: newTarget.params,
});
dispatch(navigateAction);
}
@ -204,6 +207,35 @@ export function formatTagName(name) {
return name.substring(0, 7) + '...';
}
export function getSortByItemForName(name) {
for (let i = 0; i < Constants.CLAIM_SEARCH_SORT_BY_ITEMS.length; i++) {
if (name === Constants.CLAIM_SEARCH_SORT_BY_ITEMS[i].name) {
return Constants.CLAIM_SEARCH_SORT_BY_ITEMS[i];
}
}
return null;
}
export function getOrderBy(item) {
let orderBy = [];
switch (item.name) {
case Constants.SORT_BY_HOT:
orderBy = Constants.DEFAULT_ORDER_BY;
break;
case Constants.SORT_BY_NEW:
orderBy = ['release_time'];
break;
case Constants.SORT_BY_TOP:
orderBy = [Constants.ORDER_BY_EFFECTIVE_AMOUNT];
break;
}
return orderBy;
}
// i18n placeholder until we find a good react-native i18n module
export function __(str) {
return str;