Fix release blockers (#10)

This commit is contained in:
Akinwale Ariwodola 2019-08-10 07:55:12 +01:00 committed by GitHub
parent 4b7f3f140a
commit 1e0a636b4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 405 additions and 241 deletions

8
package-lock.json generated
View file

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

View file

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

View file

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

View file

@ -1,9 +1,9 @@
import React from 'react'; 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 { ActivityIndicator, Picker, Text, TextInput, TouchableOpacity, View } from 'react-native';
import Button from 'component/button'; import Button from 'component/button';
import Colors from 'styles/colors'; 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 Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from 'component/link';
import channelSelectorStyle from 'styles/channelSelector'; import channelSelectorStyle from 'styles/channelSelector';
@ -102,7 +102,7 @@ export default class ChannelSelector extends React.PureComponent {
const { balance, createChannel, onChannelChange, notify } = this.props; const { balance, createChannel, onChannelChange, notify } = this.props;
const { newChannelBid, newChannelName } = this.state; 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.' }); notify({ message: 'Your channel name contains invalid characters.' });
return; return;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { KeyboardAvoidingView, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { KeyboardAvoidingView, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { MATURE_TAGS } from 'lbry-redux';
import Tag from 'component/tag'; import Tag from 'component/tag';
import tagStyle from 'styles/tag'; import tagStyle from 'styles/tag';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
@ -66,7 +67,7 @@ export default class TagSearch extends React.PureComponent {
}; };
render() { render() {
const { name, style, type, selectedTags = [] } = this.props; const { name, style, type, selectedTags = [], showNsfwTags } = this.props;
return ( return (
<View> <View>
@ -85,6 +86,22 @@ export default class TagSearch extends React.PureComponent {
))} ))}
</View> </View>
</KeyboardAvoidingView> </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>
); );
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,7 +21,7 @@ class DownloadsPage extends React.PureComponent {
componentWillMount() { componentWillMount() {
const { navigation } = this.props; const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); // this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
} }
componentWillUnmount() { componentWillUnmount() {
@ -44,7 +44,7 @@ class DownloadsPage extends React.PureComponent {
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { currentRoute } = nextProps; const { currentRoute } = nextProps;
const { currentRoute: prevRoute } = this.props; 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(); this.onComponentFocused();
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@ import React from 'react';
import { SETTINGS } from 'lbry-redux'; import { SETTINGS } from 'lbry-redux';
import { Text, View, ScrollView, Switch, NativeModules } from 'react-native'; import { Text, View, ScrollView, Switch, NativeModules } from 'react-native';
import { navigateBack } from 'utils/helper'; 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 PageHeader from 'component/pageHeader';
import settingsStyle from 'styles/settings'; import settingsStyle from 'styles/settings';
@ -15,7 +15,7 @@ class SettingsPage extends React.PureComponent {
componentWillMount() { componentWillMount() {
const { navigation } = this.props; const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); // this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
} }
componentWillUnmount() { componentWillUnmount() {

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { View, ScrollView, Text } from 'react-native'; 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 TransactionList from 'component/transactionList';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import walletStyle from 'styles/wallet'; import walletStyle from 'styles/wallet';
@ -10,7 +10,7 @@ class TransactionHistoryPage extends React.PureComponent {
componentWillMount() { componentWillMount() {
const { navigation } = this.props; const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); // this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
} }
componentWillUnmount() { componentWillUnmount() {

View file

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

View file

@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import { Lbry } from 'lbry-redux'; 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 AsyncStorage from '@react-native-community/async-storage';
import Button from 'component/button'; import Button from 'component/button';
import Link from 'component/link'; import Link from 'component/link';
import Colors from 'styles/colors'; 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 firstRunStyle from 'styles/firstRun';
import rewardStyle from 'styles/reward'; import rewardStyle from 'styles/reward';
@ -44,11 +44,12 @@ class EmailVerifyPage extends React.PureComponent {
notify({ message: String(emailNewErrorMessage), isError: true }); notify({ message: String(emailNewErrorMessage), isError: true });
this.setState({ verifyStarted: false }); this.setState({ verifyStarted: false });
} else { } else {
NativeModules.Firebase.track('email_added', { email: this.state.email });
this.setState({ phase: Constants.PHASE_VERIFICATION }); this.setState({ phase: Constants.PHASE_VERIFICATION });
if (setEmailVerificationPhase) { if (setEmailVerificationPhase) {
setEmailVerificationPhase(true); 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'); 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 { NavigationActions, StackActions } from 'react-navigation';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors'; 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 EmailVerifyPage from './internal/email-verify-page';
import ManualVerifyPage from './internal/manual-verify-page'; import ManualVerifyPage from './internal/manual-verify-page';
import PhoneVerifyPage from './internal/phone-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) { if (this.state.isEmailVerified && this.state.isRewardApproved) {
// verification steps already completed // verification steps already completed
// simply navigate back to the rewards page // simply navigate back to the rewards page
if (user.primary_email) {
NativeModules.Firebase.track('reward_eligibility_completed', { email: user.primary_email });
}
navigation.goBack(); navigation.goBack();
} }
} }

View file

@ -9,7 +9,7 @@ import WalletSyncDriver from 'component/walletSyncDriver';
import Button from 'component/button'; import Button from 'component/button';
import Link from 'component/link'; import Link from 'component/link';
import UriBar from 'component/uriBar'; 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'; import walletStyle from 'styles/wallet';
class WalletPage extends React.PureComponent { class WalletPage extends React.PureComponent {
@ -17,7 +17,7 @@ class WalletPage extends React.PureComponent {
componentWillMount() { componentWillMount() {
const { navigation } = this.props; const { navigation } = this.props;
this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); // this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
} }
componentWillUnmount() { 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({ dispatch({
type: Constants.ACTION_PUSH_DRAWER_STACK, type: Constants.ACTION_PUSH_DRAWER_STACK,
data: routeName, data: { routeName, params },
}); });
export const doPopDrawerStack = () => dispatch => export const doPopDrawerStack = () => dispatch =>

View file

@ -1,4 +1,5 @@
import { ACTIONS } from 'lbry-redux'; import { ACTIONS } from 'lbry-redux';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
export function doSetClientSetting(key, value) { export function doSetClientSetting(key, value) {
return dispatch => { 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 reducers = {};
const defaultState = { 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, playerVisible: false,
currentRoute: null, currentRoute: null,
}; };
@ -13,11 +13,11 @@ reducers[Constants.ACTION_SET_PLAYER_VISIBLE] = (state, action) =>
}); });
reducers[Constants.ACTION_PUSH_DRAWER_STACK] = (state, action) => { reducers[Constants.ACTION_PUSH_DRAWER_STACK] = (state, action) => {
const routeName = action.data; const { routeName, params } = action.data;
const newStack = state.stack.slice(); const newStack = state.stack.slice();
if (routeName !== newStack[newStack.length - 1]) { if (routeName !== newStack[newStack.length - 1].route) {
newStack.push(routeName); newStack.push({ route: routeName, params });
} }
return { return {

View file

@ -1,8 +1,10 @@
import { ACTIONS } from 'lbry-redux'; import { ACTIONS } from 'lbry-redux';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
const reducers = {}; const reducers = {};
const defaultState = { const defaultState = {
clientSettings: {}, clientSettings: {},
sortByItemName: Constants.SORT_BY_HOT,
}; };
reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => { 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) { export default function reducer(state = defaultState, action) {
const handler = reducers[action.type]; const handler = reducers[action.type];
if (handler) return handler(state, action); if (handler) return handler(state, action);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,6 +30,14 @@ const tagStyle = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
flexWrap: 'wrap', flexWrap: 'wrap',
}, },
nsfwTagsContainer: {
marginTop: 8,
},
nsfwTagsTitle: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
marginBottom: 4,
},
}); });
export default tagStyle; 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 target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route, params } = target;
navigation.goBack(navigation.state.key); navigation.goBack(navigation.state.key);
if (DrawerRoutes.indexOf(target) === -1 && isURIValid(target)) { if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
navigateToUri(navigation, target, null, true); navigateToUri(navigation, route, null, true);
} else { } else {
navigation.navigate({ routeName: target }); navigation.navigate({ routeName: route, params });
} }
} }
@ -166,13 +167,15 @@ export function dispatchNavigateBack(dispatch, nav, drawerStack) {
dispatch(doPopDrawerStack()); dispatch(doPopDrawerStack());
const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0]; const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route } = target;
dispatch(NavigationActions.back()); dispatch(NavigationActions.back());
if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
if (DrawerRoutes.indexOf(target) === -1 && isURIValid(target)) { dispatchNavigateToUri(dispatch, nav, route, true);
dispatchNavigateToUri(dispatch, nav, target, true);
} else { } else {
const newTarget = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const navigateAction = NavigationActions.navigate({ const navigateAction = NavigationActions.navigate({
routeName: drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0], routeName: newTarget.route,
params: newTarget.params,
}); });
dispatch(navigateAction); dispatch(navigateAction);
} }
@ -204,6 +207,35 @@ export function formatTagName(name) {
return name.substring(0, 7) + '...'; 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 // i18n placeholder until we find a good react-native i18n module
export function __(str) { export function __(str) {
return str; return str;