rework discovery views with new/top/trending sorting #25

Merged
akinwale merged 9 commits from content-views into master 2019-08-20 10:03:34 +02:00
38 changed files with 670 additions and 291 deletions
src
component
AppNavigator.js
button
claimList
drawerContent
constants.jsindex.js
page
about
channel
discover
downloads
file
firstRun
publish
publishes
rewards
search
settings
splash
subscriptions
tag
transactionHistory
trending
verification
wallet
redux
actions
reducers
selectors
styles
utils

View file

@ -141,7 +141,7 @@ const drawer = createDrawerNavigator(
Trending: { Trending: {
screen: TrendingPage, screen: TrendingPage,
navigationOptions: { navigationOptions: {
title: 'Trending', title: 'All Content',
drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />, drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />,
}, },
}, },

View file

@ -34,14 +34,14 @@ export default class Button extends React.PureComponent {
} }
let renderIcon = ( let renderIcon = (
<Icon name={icon} size={18} color={iconColor ? iconColor : 'light' === theme ? Colors.DarkGrey : Colors.White} /> <Icon name={icon} size={16} color={iconColor || (theme === 'light' ? Colors.DarkGrey : Colors.White)} />
); );
if (solid) { if (solid) {
renderIcon = ( renderIcon = (
<Icon <Icon
name={icon} name={icon}
size={18} size={16}
color={iconColor ? iconColor : 'light' === theme ? Colors.DarkGrey : Colors.White} color={iconColor || (theme === 'light' ? Colors.DarkGrey : Colors.White)}
solid solid
/> />
); );

View file

@ -21,17 +21,14 @@ class ClaimList extends React.PureComponent {
state = { state = {
currentPage: 1, // initial page load is page 1 currentPage: 1, // initial page load is page 1
subscriptionsView: false, // whether or not this claim list is for subscriptions subscriptionsView: false, // whether or not this claim list is for subscriptions
trendingForAllView: false,
lastPageReached: false, lastPageReached: false,
}; };
componentDidMount() { componentDidMount() {
const { channelIds, trendingForAll } = this.props; const { channelIds } = this.props;
if (channelIds) { if (channelIds) {
this.setState({ subscriptionsView: true }); this.setState({ subscriptionsView: true });
} else if (trendingForAll) {
this.setState({ trendingForAllView: true });
} }
this.doClaimSearch(); this.doClaimSearch();
@ -44,18 +41,16 @@ class ClaimList extends React.PureComponent {
searchByTags, searchByTags,
tags: prevTags, tags: prevTags,
channelIds: prevChannelIds, channelIds: prevChannelIds,
trendingForAll: prevTrendingForAll,
time: prevTime, time: prevTime,
showNsfwContent, showNsfwContent,
} = prevProps; } = prevProps;
const { claimSearchByQuery, orderBy, tags, channelIds, trendingForAll, time } = this.props; const { claimSearchByQuery, orderBy, tags, channelIds, time } = this.props;
if ( if (
!_.isEqual(orderBy, prevOrderBy) || !_.isEqual(orderBy, prevOrderBy) ||
!_.isEqual(tags, prevTags) || !_.isEqual(tags, prevTags) ||
!_.isEqual(channelIds, prevChannelIds) || !_.isEqual(channelIds, prevChannelIds) ||
time !== prevTime || time !== prevTime
trendingForAll !== prevTrendingForAll
) { ) {
// reset to page 1 because the order, tags or channelIds changed // reset to page 1 because the order, tags or channelIds changed
this.setState({ currentPage: 1 }, () => { this.setState({ currentPage: 1 }, () => {
@ -63,15 +58,12 @@ class ClaimList extends React.PureComponent {
this.scrollView.scrollToOffset({ animated: true, offset: 0 }); this.scrollView.scrollToOffset({ animated: true, offset: 0 });
} }
if (trendingForAll || (prevChannelIds && channelIds)) { if (prevChannelIds && channelIds) {
if (channelIds) { if (channelIds) {
this.setState({ subscriptionsView: true }); this.setState({ subscriptionsView: true });
} }
if (trendingForAll) {
this.setState({ trendingForAllView: true });
}
} else if (tags && tags.length > 0) { } else if (tags && tags.length > 0) {
this.setState({ subscriptionsView: false, trendingForAllView: false }); this.setState({ subscriptionsView: false });
} }
this.doClaimSearch(); this.doClaimSearch();
@ -80,15 +72,8 @@ class ClaimList extends React.PureComponent {
} }
buildClaimSearchOptions() { buildClaimSearchOptions() {
const { const { orderBy = Constants.DEFAULT_ORDER_BY, channelIds, showNsfwContent, tags, time } = this.props;
orderBy = Constants.DEFAULT_ORDER_BY, const { currentPage, subscriptionsView } = this.state;
channelIds,
showNsfwContent,
tags,
time,
trendingForAll,
} = this.props;
const { currentPage, subscriptionsView, trendingForAllView } = this.state;
const options = { const options = {
order_by: orderBy, order_by: orderBy,
@ -99,7 +84,7 @@ class ClaimList extends React.PureComponent {
if (channelIds) { if (channelIds) {
options.channel_ids = channelIds; options.channel_ids = channelIds;
} else if (!trendingForAll && !trendingForAllView && tags && tags.length > 0) { } else if (tags && tags.length > 0) {
options.any_tags = tags; options.any_tags = tags;
} }
if (!showNsfwContent) { if (!showNsfwContent) {
@ -156,7 +141,7 @@ class ClaimList extends React.PureComponent {
if (tags.length === 1) { if (tags.length === 1) {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: 'tagPage', params: { tag: tags[0] } }); navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: 'tagPage', params: { tag: tags[0] } });
} else { } else {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TRENDING }); navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TRENDING, params: { filterForTags: true } });
} }
}; };
@ -176,8 +161,16 @@ class ClaimList extends React.PureComponent {
}; };
renderVerticalItem = ({ item }) => { renderVerticalItem = ({ item }) => {
const { navigation } = this.props; const { hideChannel, navigation } = this.props;
return <FileListItem key={item} uri={item} style={claimListStyle.verticalListItem} navigation={navigation} />; return (
<FileListItem
key={item}
uri={item}
hideChannel={hideChannel}
style={claimListStyle.verticalListItem}
navigation={navigation}
/>
);
}; };
renderHorizontalItem = ({ item }) => { renderHorizontalItem = ({ item }) => {
@ -208,7 +201,7 @@ class ClaimList extends React.PureComponent {
style, style,
claimSearchByQuery, claimSearchByQuery,
} = this.props; } = this.props;
const { subscriptionsView, trendingForAllView } = this.state; const { subscriptionsView } = this.state;
const options = this.buildClaimSearchOptions(); const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options); const claimSearchKey = createNormalizedClaimSearchKey(options);

View file

@ -1,34 +1,76 @@
import React from 'react'; import React from 'react';
import { DrawerItems, SafeAreaView } from 'react-navigation'; import { DrawerItems, SafeAreaView } from 'react-navigation';
import { ScrollView } from 'react-native'; import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
import Constants from 'constants'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5';
import discoverStyle from 'styles/discover'; import discoverStyle from 'styles/discover';
const groupedMenuItems = {
'Find content': [
{ icon: 'hashtag', label: 'Your tags', route: Constants.FULL_ROUTE_NAME_DISCOVER },
{ icon: 'heart', solid: true, label: 'Subscriptions', route: Constants.DRAWER_ROUTE_SUBSCRIPTIONS },
{ icon: 'globe-americas', label: 'All content', route: Constants.DRAWER_ROUTE_TRENDING },
],
'Your content': [
{ icon: 'download', label: 'Library', route: Constants.DRAWER_ROUTE_MY_LBRY },
{ icon: 'cloud-upload-alt', label: 'Publishes', route: Constants.DRAWER_ROUTE_PUBLISHES },
{ icon: 'upload', label: 'New publish', route: Constants.DRAWER_ROUTE_PUBLISH },
],
Wallet: [
{ icon: 'wallet', label: 'Wallet', route: Constants.FULL_ROUTE_NAME_WALLET },
{ icon: 'award', label: 'Rewards', route: Constants.DRAWER_ROUTE_REWARDS },
],
Settings: [
{ icon: 'cog', label: 'Settings', route: Constants.DRAWER_ROUTE_SETTINGS },
{ icon: 'info', label: 'About', route: Constants.DRAWER_ROUTE_ABOUT },
],
};
const groupNames = Object.keys(groupedMenuItems);
class DrawerContent extends React.PureComponent { class DrawerContent extends React.PureComponent {
render() { render() {
const props = this.props; const { activeTintColor, navigation, onItemPress } = this.props;
const { navigation, onItemPress } = props; const { state } = navigation;
const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null;
return ( return (
<ScrollView> <ScrollView contentContainerStyle={discoverStyle.menuScrollContent}>
<SafeAreaView style={discoverStyle.drawerContentContainer} forceInset={{ top: 'always', horizontal: 'never' }}> <SafeAreaView style={discoverStyle.drawerContentContainer} forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {groupNames.map(groupName => {
{...props} const menuItems = groupedMenuItems[groupName];
onItemPress={route => {
const { routeName } = route.route;
if (Constants.FULL_ROUTE_NAME_DISCOVER === routeName) {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_DISCOVER });
return;
}
if (Constants.FULL_ROUTE_NAME_WALLET === routeName) { return (
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_WALLET }); <View key={groupName} style={discoverStyle.menuGroup}>
return; {groupNames[3] !== groupName && (
} <Text key={`${groupName}-title`} style={discoverStyle.menuGroupName}>
{groupName}
onItemPress(route); </Text>
}} )}
/> {menuItems.map(item => {
const focused = activeItemKey === item.route;
return (
<TouchableOpacity
accessible
accessibilityLabel={item.label}
style={[discoverStyle.menuItemTouchArea, focused ? discoverStyle.menuItemTouchAreaFocused : null]}
key={item.label}
onPress={() => navigation.navigate({ routeName: item.route })}
delayPressIn={0}
>
<View style={discoverStyle.menuItemIcon}>
<Icon name={item.icon} size={16} solid={item.solid} color={focused ? activeTintColor : null} />
</View>
<Text style={[discoverStyle.menuItem, focused ? discoverStyle.menuItemFocused : null]}>
{item.label}
</Text>
</TouchableOpacity>
);
})}
</View>
);
})}
</SafeAreaView> </SafeAreaView>
</ScrollView> </ScrollView>
); );

View file

@ -54,6 +54,7 @@ const Constants = {
ACTION_REACT_NAVIGATION_REPLACE: 'Navigation/REPLACE', ACTION_REACT_NAVIGATION_REPLACE: 'Navigation/REPLACE',
ACTION_SORT_BY_ITEM_CHANGED: 'SORT_BY_ITEM_CHANGED', ACTION_SORT_BY_ITEM_CHANGED: 'SORT_BY_ITEM_CHANGED',
ACTION_TIME_ITEM_CHANGED: 'TIME_ITEM_CHANGED',
ORIENTATION_HORIZONTAL: 'horizontal', ORIENTATION_HORIZONTAL: 'horizontal',
ORIENTATION_VERTICAL: 'vertical', ORIENTATION_VERTICAL: 'vertical',

View file

@ -43,6 +43,7 @@ import thunk from 'redux-thunk';
const globalExceptionHandler = (error, isFatal) => { const globalExceptionHandler = (error, isFatal) => {
if (error && NativeModules.Firebase) { if (error && NativeModules.Firebase) {
console.log(error);
NativeModules.Firebase.logException(isFatal, error.message ? error.message : 'No message', JSON.stringify(error)); NativeModules.Firebase.logException(isFatal, error.message ? error.message : 'No message', JSON.stringify(error));
} }
}; };

View file

@ -43,6 +43,7 @@ class AboutPage extends React.PureComponent {
const { pushDrawerStack, setPlayerVisible } = this.props; const { pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('About');
if (NativeModules.VersionInfo) { if (NativeModules.VersionInfo) {
NativeModules.VersionInfo.getAppVersion().then(version => { NativeModules.VersionInfo.getAppVersion().then(version => {

View file

@ -1,26 +1,23 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { doFetchClaimsByChannel, makeSelectClaimForUri } from 'lbry-redux';
doFetchClaimsByChannel,
makeSelectClaimForUri,
makeSelectClaimsInChannelForCurrentPageState,
makeSelectFetchingChannelClaims,
makeSelectTotalPagesForChannel,
} from 'lbry-redux';
import { doPopDrawerStack } from 'redux/actions/drawer'; import { doPopDrawerStack } from 'redux/actions/drawer';
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { selectDrawerStack } from 'redux/selectors/drawer'; import { selectDrawerStack } from 'redux/selectors/drawer';
import { selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
import ChannelPage from './view'; import ChannelPage from './view';
const select = (state, props) => ({ const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state),
drawerStack: selectDrawerStack(state), drawerStack: selectDrawerStack(state),
fetching: makeSelectFetchingChannelClaims(props.uri)(state), sortByItem: selectSortByItem(state),
totalPages: makeSelectTotalPagesForChannel(props.uri, 10)(state), // Update to use a default PAGE_SIZE constant timeItem: selectTimeItem(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)), fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
popDrawerStack: () => dispatch(doPopDrawerStack()), popDrawerStack: () => dispatch(doPopDrawerStack()),
setSortByItem: item => dispatch(doSetSortByItem(item)),
setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect( export default connect(

View file

@ -1,113 +1,111 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { ActivityIndicator, Dimensions, Image, ScrollView, Text, TouchableOpacity, View } from 'react-native'; import {
ActivityIndicator,
Dimensions,
Image,
NativeModules,
ScrollView,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view'; import { TabView, SceneMap } from 'react-native-tab-view';
import { normalizeURI } from 'lbry-redux'; import { normalizeURI } from 'lbry-redux';
import { navigateBack } from 'utils/helper'; import { navigateBack, getOrderBy } from 'utils/helper';
import ChannelIconItem from 'component/channelIconItem';
import ClaimList from 'component/claimList';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Button from 'component/button'; import Button from 'component/button';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from 'component/link';
import FileList from 'component/fileList'; import ModalPicker from 'component/modalPicker';
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 SubscribeNotificationButton from 'component/subscribeNotificationButton';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import channelIconStyle from 'styles/channelIcon';
import channelPageStyle from 'styles/channelPage'; import channelPageStyle from 'styles/channelPage';
import discoverStyle from 'styles/discover';
class ChannelPage extends React.PureComponent { class ChannelPage extends React.PureComponent {
state = { state = {
page: 1, autoStyle: null,
showPageButtons: false, showSortPicker: false,
showTimePicker: false,
orderBy: Constants.DEFAULT_ORDER_BY,
activeTab: Constants.CONTENT_TAB, activeTab: Constants.CONTENT_TAB,
}; };
componentDidMount() { componentWillMount() {
const { uri, page, claimsInChannel, fetchClaims, fetchClaimCount } = this.props; this.setState({
autoStyle:
if (!claimsInChannel || !claimsInChannel.length) { ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
fetchClaims(uri, page || this.state.page); });
}
} }
handlePreviousPage = () => { componentDidMount() {
const { uri, fetchClaims } = this.props; NativeModules.Firebase.setCurrentScreen('Channel');
if (this.state.page > 1) { }
this.setState({ page: this.state.page - 1, showPageButtons: false }, () => {
fetchClaims(uri, this.state.page); handleSortByItemSelected = item => {
}); const { setSortByItem } = this.props;
} setSortByItem(item);
this.setState({ orderBy: getOrderBy(item), showSortPicker: false });
}; };
handleNextPage = () => { handleTimeItemSelected = item => {
const { uri, fetchClaims, totalPages } = this.props; const { setTimeItem } = this.props;
if (this.state.page < totalPages) { setTimeItem(item);
this.setState({ page: this.state.page + 1, showPageButtons: false }, () => { this.setState({ showTimePicker: false });
fetchClaims(uri, this.state.page); };
});
} listHeader = () => {
const { sortByItem, timeItem } = this.props;
return (
<View style={channelPageStyle.listHeader}>
<View style={discoverStyle.pickerRow}>
<View style={discoverStyle.leftPickerRow}>
<TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
<Text style={discoverStyle.tagSortText}>{sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
{Constants.SORT_BY_TOP === sortByItem.name && (
<TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
<Text style={discoverStyle.tagSortText}>{timeItem.label}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
</View>
</View>
</View>
);
}; };
renderContent = () => { renderContent = () => {
const { fetching, claimsInChannel, totalPages, navigation } = this.props; const { claim, navigation, timeItem } = this.props;
let contentList; let channelId;
if (fetching) { if (claim) {
contentList = ( channelId = claim.claim_id;
<View style={channelPageStyle.busyContainer}>
<ActivityIndicator size="large" color={Colors.NextLbryGreen} />
<Text style={channelPageStyle.infoText}>Fetching content...</Text>
</View>
);
} else {
contentList =
claimsInChannel && claimsInChannel.length ? (
<FileList
sortByHeight
hideFilter
fileInfos={claimsInChannel}
navigation={navigation}
style={channelPageStyle.fileList}
contentContainerStyle={channelPageStyle.fileListContent}
onEndReached={() => this.setState({ showPageButtons: true })}
/>
) : (
<View style={channelPageStyle.busyContainer}>
<Text style={channelPageStyle.infoText}>No content found.</Text>
</View>
);
}
let pageButtons;
if (totalPages > 1 && this.state.showPageButtons) {
pageButtons = (
<View style={channelPageStyle.pageButtons}>
<View>
{this.state.page > 1 && (
<Button
style={channelPageStyle.button}
text={'Previous'}
disabled={!!fetching}
onPress={this.handlePreviousPage}
/>
)}
</View>
{this.state.page < totalPages && (
<Button
style={[channelPageStyle.button, channelPageStyle.nextButton]}
text={'Next'}
disabled={!!fetching}
onPress={this.handleNextPage}
/>
)}
</View>
);
} }
return ( return (
<View style={channelPageStyle.contentTab}> <View style={channelPageStyle.contentTab}>
{contentList} {channelId && (
{pageButtons} <ClaimList
ListHeaderComponent={this.listHeader}
hideChannel
orderBy={this.state.orderBy}
time={timeItem.name}
navigation={navigation}
orientation={Constants.ORIENTATION_VERTICAL}
channelIds={[channelId]}
style={channelPageStyle.claimList}
/>
)}
</View> </View>
); );
}; };
@ -162,10 +160,16 @@ class ChannelPage extends React.PureComponent {
}; };
render() { render() {
const { fetching, claimsInChannel, claim, navigation, totalPages, uri, drawerStack, popDrawerStack } = this.props; const { claim, navigation, uri, drawerStack, popDrawerStack, sortByItem, timeItem } = this.props;
const { name, permanent_url: permanentUrl } = claim; const { name, permanent_url: permanentUrl } = claim;
const { autoStyle, showSortPicker, showTimePicker } = this.state;
let thumbnailUrl, coverUrl, title, fullUri; let thumbnailUrl,
coverUrl,
title,
fullUri,
displayName = null,
substrIndex = 0;
if (claim) { if (claim) {
if (claim.value) { if (claim.value) {
title = claim.value.title; title = claim.value.title;
@ -177,6 +181,8 @@ class ChannelPage extends React.PureComponent {
} }
} }
displayName = title || claim.name;
substrIndex = displayName.startsWith('@') ? 1 : 0;
fullUri = normalizeURI(`${claim.name}#${claim.claim_id}`); fullUri = normalizeURI(`${claim.name}#${claim.claim_id}`);
} }
@ -200,16 +206,15 @@ class ChannelPage extends React.PureComponent {
<Text style={channelPageStyle.channelName}>{title && title.trim().length > 0 ? title : name}</Text> <Text style={channelPageStyle.channelName}>{title && title.trim().length > 0 ? title : name}</Text>
</View> </View>
<View style={channelPageStyle.avatarImageContainer}> <View style={[channelPageStyle.avatarImageContainer, autoStyle]}>
<Image {thumbnailUrl && (
style={channelPageStyle.avatarImage} <Image style={channelPageStyle.avatarImage} resizeMode={'cover'} source={{ uri: thumbnailUrl }} />
resizeMode={'cover'} )}
source={ {(!thumbnailUrl || thumbnailUrl.trim().length === 0) && (
thumbnailUrl && thumbnailUrl.trim().length > 0 <Text style={channelIconStyle.autothumbCharacter}>
? { uri: thumbnailUrl } {displayName.substring(substrIndex, substrIndex + 1).toUpperCase()}
: require('../../assets/default_avatar.jpg') </Text>
} )}
/>
</View> </View>
<View style={channelPageStyle.subscribeButtonContainer}> <View style={channelPageStyle.subscribeButtonContainer}>
@ -242,6 +247,25 @@ class ChannelPage extends React.PureComponent {
{Constants.CONTENT_TAB === this.state.activeTab && this.renderContent()} {Constants.CONTENT_TAB === this.state.activeTab && this.renderContent()}
{Constants.ABOUT_TAB === this.state.activeTab && this.renderAbout()} {Constants.ABOUT_TAB === this.state.activeTab && this.renderAbout()}
</View> </View>
{showSortPicker && (
<ModalPicker
title={__('Sort content by')}
onOverlayPress={() => this.setState({ showSortPicker: false })}
onItemSelected={this.handleSortByItemSelected}
selectedItem={sortByItem}
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/>
)}
{showTimePicker && (
<ModalPicker
title={__('Content from')}
onOverlayPress={() => this.setState({ showTimePicker: false })}
onItemSelected={this.handleTimeItemSelected}
selectedItem={timeItem}
items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/>
)}
</View> </View>
); );
} }

View file

@ -11,8 +11,8 @@ import {
selectSubscriptionClaims, selectSubscriptionClaims,
selectUnreadSubscriptions, selectUnreadSubscriptions,
} from 'lbryinc'; } from 'lbryinc';
import { doSetClientSetting, doSetSortByItem } from 'redux/actions/settings'; import { doSetClientSetting, doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { makeSelectClientSetting, selectSortByItem } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectSortByItem, selectTimeItem } 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';
@ -27,6 +27,7 @@ const select = 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), sortByItem: selectSortByItem(state),
timeItem: selectTimeItem(state),
unreadSubscriptions: selectUnreadSubscriptions(state), unreadSubscriptions: selectUnreadSubscriptions(state),
}); });
@ -39,6 +40,7 @@ const perform = dispatch => ({
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)), setSortByItem: item => dispatch(doSetSortByItem(item)),
setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect( export default connect(

View file

@ -33,10 +33,13 @@ class DiscoverPage extends React.PureComponent {
remainingTags: [], remainingTags: [],
showModalTagSelector: false, showModalTagSelector: false,
showSortPicker: false, showSortPicker: false,
showTimePicker: false,
orderBy: Constants.DEFAULT_ORDER_BY, orderBy: Constants.DEFAULT_ORDER_BY,
}; };
componentDidMount() { componentDidMount() {
NativeModules.Firebase.setCurrentScreen('Your tags');
// Track the total time taken if this is the first launch // Track the total time taken if this is the first launch
AsyncStorage.getItem('firstLaunchTime').then(startTime => { AsyncStorage.getItem('firstLaunchTime').then(startTime => {
if (startTime !== null && !isNaN(parseInt(startTime, 10))) { if (startTime !== null && !isNaN(parseInt(startTime, 10))) {
@ -78,6 +81,12 @@ class DiscoverPage extends React.PureComponent {
this.setState({ orderBy, showSortPicker: false }); this.setState({ orderBy, showSortPicker: false });
}; };
handleTimeItemSelected = item => {
const { setTimeItem } = this.props;
setTimeItem(item);
this.setState({ showTimePicker: false });
};
subscriptionForUri = (uri, channelName) => { subscriptionForUri = (uri, channelName) => {
const { allSubscriptions } = this.props; const { allSubscriptions } = this.props;
const { claimId, claimName } = parseURI(uri); const { claimId, claimName } = parseURI(uri);
@ -230,26 +239,41 @@ class DiscoverPage extends React.PureComponent {
}); });
} else { } else {
// navigate to the trending page // navigate to the trending page
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TRENDING }); navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TRENDING, params: { filterForTags: true } });
} }
}; };
sectionListHeader = () => ( sectionListHeader = () => {
<View style={discoverStyle.titleRow}> const { sortByItem, timeItem } = this.props;
<Text style={discoverStyle.pageTitle}>Explore</Text> return (
<View style={discoverStyle.rightTitleRow}> <View style={discoverStyle.listHeader}>
<Link <View style={discoverStyle.titleRow}>
style={discoverStyle.customizeLink} <Text style={discoverStyle.pageTitle}>Your tags</Text>
text={'Customize'} </View>
onPress={() => this.setState({ showModalTagSelector: true })} <View style={discoverStyle.pickerRow}>
/> <View style={discoverStyle.leftPickerRow}>
<TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}> <TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
<Text style={discoverStyle.tagSortText}>{this.props.sortByItem.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>
{Constants.SORT_BY_TOP === sortByItem.name && (
<TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
<Text style={discoverStyle.tagSortText}>{timeItem.label}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
</View>
<Link
style={discoverStyle.customizeLink}
text={'Customize'}
onPress={() => this.setState({ showModalTagSelector: true })}
/>
</View>
</View> </View>
</View> );
); };
sectionListFooter = () => { sectionListFooter = () => {
const { remainingTags } = this.state; const { remainingTags } = this.state;
@ -279,7 +303,7 @@ class DiscoverPage extends React.PureComponent {
<ClaimList <ClaimList
key={item.sort().join(',')} key={item.sort().join(',')}
orderBy={this.state.orderBy} orderBy={this.state.orderBy}
time={Constants.TIME_WEEK} time={this.props.timeItem.name}
tags={item} tags={item}
morePlaceholder morePlaceholder
navigation={this.props.navigation} navigation={this.props.navigation}
@ -299,8 +323,8 @@ class DiscoverPage extends React.PureComponent {
); );
render() { render() {
const { navigation, sortByItem } = this.props; const { navigation, sortByItem, timeItem } = this.props;
const { orderBy, showModalTagSelector, showSortPicker } = this.state; const { orderBy, showModalTagSelector, showSortPicker, showTimePicker } = this.state;
return ( return (
<View style={discoverStyle.container}> <View style={discoverStyle.container}>
@ -318,7 +342,9 @@ class DiscoverPage extends React.PureComponent {
sections={this.buildSections()} sections={this.buildSections()}
keyExtractor={(item, index) => item} keyExtractor={(item, index) => item}
/> />
{!showModalTagSelector && !showSortPicker && <FloatingWalletBalance navigation={navigation} />} {!showModalTagSelector && !showSortPicker && !showTimePicker && (
<FloatingWalletBalance navigation={navigation} />
)}
{showModalTagSelector && ( {showModalTagSelector && (
<ModalTagSelector <ModalTagSelector
onOverlayPress={() => this.setState({ showModalTagSelector: false })} onOverlayPress={() => this.setState({ showModalTagSelector: false })}
@ -334,6 +360,15 @@ class DiscoverPage extends React.PureComponent {
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS} items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/> />
)} )}
{showTimePicker && (
<ModalPicker
title={__('Content from')}
onOverlayPress={() => this.setState({ showTimePicker: false })}
onItemSelected={this.handleTimeItemSelected}
selectedItem={timeItem}
items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/>
)}
</View> </View>
); );
} }

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Lbry, buildURI, normalizeURI } from 'lbry-redux'; import { Lbry, buildURI, normalizeURI } from 'lbry-redux';
import { ActivityIndicator, Button, FlatList, Text, TextInput, View, ScrollView } from 'react-native'; import { ActivityIndicator, Button, FlatList, NativeModules, Text, TextInput, View, ScrollView } from 'react-native';
import { navigateToUri, uriFromFileInfo } from 'utils/helper'; import { navigateToUri, uriFromFileInfo } from 'utils/helper';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
@ -34,6 +34,8 @@ class DownloadsPage extends React.PureComponent {
const { fetchMyClaims, fileList, pushDrawerStack, setPlayerVisible } = this.props; const { fetchMyClaims, fileList, pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Library');
fetchMyClaims(); fetchMyClaims();
fileList(); fileList();
}; };

View file

@ -93,6 +93,7 @@ class FilePage extends React.PureComponent {
onComponentFocused = () => { onComponentFocused = () => {
StatusBar.setHidden(false); StatusBar.setHidden(false);
NativeModules.Firebase.setCurrentScreen('File');
DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted);
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);

View file

@ -45,6 +45,8 @@ class FirstRunScreen extends React.PureComponent {
}); });
if (NativeModules.FirstRun) { if (NativeModules.FirstRun) {
NativeModules.Firebase.setCurrentScreen('First Run');
NativeModules.FirstRun.isFirstRun().then(firstRun => { NativeModules.FirstRun.isFirstRun().then(firstRun => {
AsyncStorage.removeItem(Constants.KEY_FIRST_RUN_EMAIL); AsyncStorage.removeItem(Constants.KEY_FIRST_RUN_EMAIL);
AsyncStorage.removeItem(Constants.KEY_EMAIL_VERIFY_PENDING); AsyncStorage.removeItem(Constants.KEY_EMAIL_VERIFY_PENDING);

View file

@ -79,6 +79,7 @@ class PublishPage extends React.PureComponent {
canUseCamera: false, canUseCamera: false,
titleFocused: false, titleFocused: false,
descriptionFocused: false, descriptionFocused: false,
loadingVideos: false,
// gallery videos // gallery videos
videos: null, videos: null,
@ -151,13 +152,20 @@ class PublishPage extends React.PureComponent {
onComponentFocused = () => { onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible } = this.props; const { pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Publish');
NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera })); NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera }));
NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath })); NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath }));
NativeModules.Gallery.getVideos().then(videos => this.setState({ videos })); this.setState(
{
loadingVideos: true,
},
() => {
NativeModules.Gallery.getVideos().then(videos => this.setState({ videos, loadingVideos: false }));
}
);
}; };
getNewUri(name, channel) { getNewUri(name, channel) {
@ -586,7 +594,7 @@ class PublishPage extends React.PureComponent {
render() { render() {
const { balance, navigation, notify, publishFormValues } = this.props; const { balance, navigation, notify, publishFormValues } = this.props;
const { canUseCamera, currentPhase, checkedThumbnails, thumbnailPath, videos } = this.state; const { canUseCamera, currentPhase, checkedThumbnails, loadingVideos, thumbnailPath, videos } = this.state;
let content; let content;
if (Constants.PHASE_SELECTOR === currentPhase) { if (Constants.PHASE_SELECTOR === currentPhase) {
@ -625,13 +633,13 @@ class PublishPage extends React.PureComponent {
</View> </View>
</View> </View>
</View> </View>
{(!videos || !thumbnailPath || checkedThumbnails.length === 0) && ( {(loadingVideos || !thumbnailPath || checkedThumbnails.length === 0) && (
<View style={publishStyle.loadingView}> <View style={publishStyle.loadingView}>
<ActivityIndicator size="large" color={Colors.NextLbryGreen} /> <ActivityIndicator size="large" color={Colors.NextLbryGreen} />
</View> </View>
)} )}
{thumbnailPath && (!videos || videos.length === 0) && ( {!loadingVideos && (!videos || videos.length === 0) && (
<View style={publishStyle.centered}> <View style={publishStyle.relativeCentered}>
<Text style={publishStyle.noVideos}> <Text style={publishStyle.noVideos}>
We could not find any videos on your device. Take a photo or record a video to get started. We could not find any videos on your device. Take a photo or record a video to get started.
</Text> </Text>

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { ActivityIndicator, Alert, FlatList, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Alert, FlatList, NativeModules, Text, 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'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
@ -35,9 +35,10 @@ class PublishesPage extends React.PureComponent {
onComponentFocused = () => { onComponentFocused = () => {
const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props; const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Publishes');
fetchMyClaims(); fetchMyClaims();
checkPendingPublishes(); checkPendingPublishes();
}; };

View file

@ -42,6 +42,8 @@ class RewardsPage extends React.PureComponent {
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Rewards');
fetchRewards(); fetchRewards();
this.setState({ this.setState({

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Lbry, parseURI, normalizeURI, isURIValid } from 'lbry-redux'; import { Lbry, parseURI, normalizeURI, isURIValid } from 'lbry-redux';
import { ActivityIndicator, Button, Text, TextInput, View, ScrollView } from 'react-native'; import { ActivityIndicator, Button, NativeModules, Text, TextInput, View, ScrollView } from 'react-native';
import { navigateToUri } from 'utils/helper'; import { navigateToUri } from 'utils/helper';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
@ -37,6 +37,7 @@ class SearchPage extends React.PureComponent {
const { pushDrawerStack, setPlayerVisible, query, search } = this.props; const { pushDrawerStack, setPlayerVisible, query, search } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Search');
const searchQuery = query || this.getSearchQuery(); const searchQuery = query || this.getSearchQuery();
if (searchQuery && searchQuery.trim().length > 0) { if (searchQuery && searchQuery.trim().length > 0) {

View file

@ -28,6 +28,7 @@ class SettingsPage extends React.PureComponent {
const { pushDrawerStack, setPlayerVisible } = this.props; const { pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Settings');
}; };
componentDidMount() { componentDidMount() {

View file

@ -239,6 +239,8 @@ class SplashScreen extends React.PureComponent {
NativeModules.Firebase.track('app_launch', null); NativeModules.Firebase.track('app_launch', null);
} }
NativeModules.Firebase.setCurrentScreen('Splash');
this.props.fetchRewardedContent(); this.props.fetchRewardedContent();
Linking.getInitialURL().then(url => { Linking.getInitialURL().then(url => {
if (url) { if (url) {

View file

@ -14,8 +14,8 @@ import {
selectShowSuggestedSubs, selectShowSuggestedSubs,
} from 'lbryinc'; } from 'lbryinc';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting, doSetTimeItem } from 'redux/actions/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectTimeItem } from 'redux/selectors/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import SubscriptionsPage from './view'; import SubscriptionsPage from './view';
@ -32,6 +32,7 @@ const select = state => ({
viewMode: selectViewMode(state), viewMode: selectViewMode(state),
firstRunCompleted: selectFirstRunCompleted(state), firstRunCompleted: selectFirstRunCompleted(state),
showSuggestedSubs: selectShowSuggestedSubs(state), showSuggestedSubs: selectShowSuggestedSubs(state),
timeItem: selectTimeItem(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -41,6 +42,7 @@ const perform = dispatch => ({
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect( export default connect(

View file

@ -11,7 +11,7 @@ import {
View, View,
} from 'react-native'; } from 'react-native';
import { buildURI, parseURI } from 'lbry-redux'; import { buildURI, parseURI } from 'lbry-redux';
import { __, uriFromFileInfo } from 'utils/helper'; import { __, 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 Button from 'component/button'; import Button from 'component/button';
@ -33,6 +33,7 @@ class SubscriptionsPage extends React.PureComponent {
state = { state = {
showingSuggestedSubs: false, showingSuggestedSubs: false,
showSortPicker: false, showSortPicker: false,
showTimePicker: false,
orderBy: ['release_time'], orderBy: ['release_time'],
filteredChannels: [], filteredChannels: [],
currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new
@ -63,6 +64,8 @@ class SubscriptionsPage extends React.PureComponent {
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Subscriptions');
doFetchMySubscriptions(); doFetchMySubscriptions();
doFetchRecommendedSubscriptions(); doFetchRecommendedSubscriptions();
}; };
@ -80,22 +83,13 @@ class SubscriptionsPage extends React.PureComponent {
} }
handleSortByItemSelected = item => { handleSortByItemSelected = item => {
let orderBy = []; this.setState({ currentSortByItem: item, orderBy: getOrderBy(item), showSortPicker: false });
switch (item.name) { };
case Constants.SORT_BY_HOT:
orderBy = Constants.DEFAULT_ORDER_BY;
break;
case Constants.SORT_BY_NEW: handleTimeItemSelected = item => {
orderBy = ['release_time']; const { setTimeItem } = this.props;
break; setTimeItem(item);
this.setState({ showTimePicker: false });
case Constants.SORT_BY_TOP:
orderBy = ['effective_amount'];
break;
}
this.setState({ currentSortByItem: item, orderBy, showSortPicker: false });
}; };
handleChannelSelected = channelUri => { handleChannelSelected = channelUri => {
@ -118,18 +112,17 @@ class SubscriptionsPage extends React.PureComponent {
suggestedChannels, suggestedChannels,
subscribedChannels, subscribedChannels,
allSubscriptions, allSubscriptions,
viewMode, doCompleteFirstRun,
doSetViewMode, doShowSuggestedSubs,
loading, loading,
loadingSuggested, loadingSuggested,
firstRunCompleted, firstRunCompleted,
doCompleteFirstRun,
doShowSuggestedSubs,
showSuggestedSubs, showSuggestedSubs,
timeItem,
unreadSubscriptions, unreadSubscriptions,
navigation, navigation,
} = this.props; } = this.props;
const { currentSortByItem, filteredChannels } = this.state; const { currentSortByItem, filteredChannels, showSortPicker, showTimePicker } = this.state;
const numberOfSubscriptions = subscribedChannels ? subscribedChannels.length : 0; const numberOfSubscriptions = subscribedChannels ? subscribedChannels.length : 0;
const hasSubscriptions = numberOfSubscriptions > 0; const hasSubscriptions = numberOfSubscriptions > 0;
@ -155,7 +148,9 @@ class SubscriptionsPage extends React.PureComponent {
<UriBar navigation={navigation} belowOverlay={this.state.showSortPicker} /> <UriBar navigation={navigation} belowOverlay={this.state.showSortPicker} />
<View style={subscriptionsStyle.titleRow}> <View style={subscriptionsStyle.titleRow}>
<Text style={subscriptionsStyle.pageTitle}>Channels you follow</Text> <Text style={subscriptionsStyle.pageTitle}>Channels you follow</Text>
{!this.state.showingSuggestedSubs && hasSubscriptions && ( </View>
{!this.state.showingSuggestedSubs && hasSubscriptions && (
<View style={subscriptionsStyle.pickerRow}>
<TouchableOpacity <TouchableOpacity
style={subscriptionsStyle.tagSortBy} style={subscriptionsStyle.tagSortBy}
onPress={() => this.setState({ showSortPicker: true })} onPress={() => this.setState({ showSortPicker: true })}
@ -163,8 +158,18 @@ class SubscriptionsPage extends React.PureComponent {
<Text style={subscriptionsStyle.tagSortText}>{currentSortByItem.label.split(' ')[0]}</Text> <Text style={subscriptionsStyle.tagSortText}>{currentSortByItem.label.split(' ')[0]}</Text>
<Icon style={subscriptionsStyle.tagSortIcon} name={'sort-down'} size={14} /> <Icon style={subscriptionsStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity> </TouchableOpacity>
)}
</View> {Constants.SORT_BY_TOP === currentSortByItem.name && (
<TouchableOpacity
style={subscriptionsStyle.tagSortBy}
onPress={() => this.setState({ showTimePicker: true })}
>
<Text style={subscriptionsStyle.tagSortText}>{timeItem.label}</Text>
<Icon style={subscriptionsStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
</View>
)}
{!this.state.showingSuggestedSubs && hasSubscriptions && !loading && ( {!this.state.showingSuggestedSubs && hasSubscriptions && !loading && (
<View style={subscriptionsStyle.subContainer}> <View style={subscriptionsStyle.subContainer}>
<SubscribedChannelList <SubscribedChannelList
@ -175,6 +180,7 @@ class SubscriptionsPage extends React.PureComponent {
style={subscriptionsStyle.claimList} style={subscriptionsStyle.claimList}
channelIds={channelIds} channelIds={channelIds}
orderBy={this.state.orderBy} orderBy={this.state.orderBy}
time={timeItem.name}
navigation={navigation} navigation={navigation}
orientation={Constants.ORIENTATION_VERTICAL} orientation={Constants.ORIENTATION_VERTICAL}
/> />
@ -217,8 +223,8 @@ class SubscriptionsPage extends React.PureComponent {
</View> </View>
)} )}
{!this.state.showSortPicker && <FloatingWalletBalance navigation={navigation} />} {!showSortPicker && !showTimePicker && <FloatingWalletBalance navigation={navigation} />}
{this.state.showSortPicker && ( {showSortPicker && (
<ModalPicker <ModalPicker
title={__('Sort content by')} title={__('Sort content by')}
onOverlayPress={() => this.setState({ showSortPicker: false })} onOverlayPress={() => this.setState({ showSortPicker: false })}
@ -227,6 +233,15 @@ class SubscriptionsPage extends React.PureComponent {
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS} items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/> />
)} )}
{showTimePicker && (
<ModalPicker
title={__('Content from')}
onOverlayPress={() => this.setState({ showTimePicker: false })}
onItemSelected={this.handleTimeItemSelected}
selectedItem={timeItem}
items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/>
)}
</View> </View>
); );
} }

View file

@ -1,19 +1,24 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags, doToggleTagFollow } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetSortByItem } from 'redux/actions/settings'; import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import { selectSortByItem } from 'redux/selectors/settings'; import { selectSortByItem, selectTimeItem } 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), sortByItem: selectSortByItem(state),
timeItem: selectTimeItem(state),
followedTags: selectFollowedTags(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)), pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setSortByItem: item => dispatch(doSetSortByItem(item)), setSortByItem: item => dispatch(doSetSortByItem(item)),
setTimeItem: item => dispatch(doSetTimeItem(item)),
toggleTagFollow: tag => dispatch(doToggleTagFollow(tag)),
}); });
export default connect( export default connect(

View file

@ -12,6 +12,7 @@ import fileListStyle from 'styles/fileList';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import FloatingWalletBalance from 'component/floatingWalletBalance'; import FloatingWalletBalance from 'component/floatingWalletBalance';
import Link from 'component/link';
import ModalPicker from 'component/modalPicker'; import ModalPicker from 'component/modalPicker';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
@ -21,8 +22,6 @@ class TagPage extends React.PureComponent {
showSortPicker: false, showSortPicker: false,
showTimePicker: false, showTimePicker: false,
orderBy: Constants.DEFAULT_ORDER_BY, orderBy: Constants.DEFAULT_ORDER_BY,
time: Constants.TIME_WEEK,
currentTimeItem: Constants.CLAIM_SEARCH_TIME_ITEMS[1],
}; };
didFocusListener; didFocusListener;
@ -41,9 +40,10 @@ class TagPage extends React.PureComponent {
onComponentFocused = () => { onComponentFocused = () => {
const { navigation, pushDrawerStack, setPlayerVisible, sortByItem } = this.props; const { navigation, pushDrawerStack, setPlayerVisible, sortByItem } = this.props;
const { tag } = navigation.state.params; const { tag } = navigation.state.params;
this.setState({ tag, sortByItem, orderBy: getOrderBy(sortByItem) }); this.setState({ tag, orderBy: getOrderBy(sortByItem) });
pushDrawerStack(Constants.DRAWER_ROUTE_TAG, navigation.state.params); pushDrawerStack(Constants.DRAWER_ROUTE_TAG, navigation.state.params);
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Tag');
}; };
componentDidMount() { componentDidMount() {
@ -65,42 +65,80 @@ class TagPage extends React.PureComponent {
}; };
handleTimeItemSelected = item => { handleTimeItemSelected = item => {
this.setState({ currentTimeItem: item, time: item.name, showTimePicker: false }); const { setTimeItem } = this.props;
setTimeItem(item);
this.setState({ showTimePicker: false });
};
isFollowingTag = tag => {
const { followedTags } = this.props;
return followedTags.map(tag => tag.name).includes(tag);
};
handleFollowTagToggle = () => {
const { toggleTagFollow } = this.props;
const { tag } = this.state;
const isFollowing = this.isFollowingTag(tag);
if (isFollowing) {
// unfollow
NativeModules.Firebase.track('tag_unfollow', { tag });
} else {
// follow
NativeModules.Firebase.track('tag_follow', { tag });
}
toggleTagFollow(tag);
if (window.persistor) {
window.persistor.flush();
}
};
listHeader = () => {
const { sortByItem, timeItem } = this.props;
const { tag } = this.state;
return (
<View style={discoverStyle.listHeader}>
<View style={discoverStyle.titleRow}>
<Text style={discoverStyle.pageTitle}>{formatTagTitle(tag)}</Text>
</View>
<View style={discoverStyle.pickerRow}>
<View style={discoverStyle.leftPickerRow}>
<TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
<Text style={discoverStyle.tagSortText}>{sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
{Constants.SORT_BY_TOP === sortByItem.name && (
<TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
<Text style={discoverStyle.tagSortText}>{timeItem.label}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
</View>
<Link
style={discoverStyle.customizeLink}
text={this.isFollowingTag(tag) ? 'Unfollow' : 'Follow'}
onPress={this.handleFollowTagToggle}
/>
</View>
</View>
);
}; };
render() { render() {
const { navigation, sortByItem } = this.props; const { navigation, sortByItem, timeItem } = this.props;
const { tag, currentTimeItem, showSortPicker, showTimePicker } = this.state; const { tag, showSortPicker, showTimePicker } = this.state;
return ( return (
<View style={discoverStyle.container}> <View style={discoverStyle.container}>
<UriBar navigation={navigation} belowOverlay={showSortPicker || showTimePicker} /> <UriBar navigation={navigation} belowOverlay={showSortPicker || showTimePicker} />
{this.state.tag && ( {this.state.tag && (
<ClaimList <ClaimList
ListHeaderComponent={ ListHeaderComponent={this.listHeader}
<View style={discoverStyle.tagTitleRow}>
<Text style={discoverStyle.tagPageTitle}>{formatTagTitle(tag)}</Text>
{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}>{sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
</View>
}
style={discoverStyle.tagPageClaimList} style={discoverStyle.tagPageClaimList}
orderBy={this.state.orderBy} orderBy={this.state.orderBy}
time={this.state.time} time={timeItem.name}
tags={[tag]} tags={[tag]}
navigation={navigation} navigation={navigation}
orientation={Constants.ORIENTATION_VERTICAL} orientation={Constants.ORIENTATION_VERTICAL}
@ -112,7 +150,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.sortByItem} selectedItem={sortByItem}
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS} items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/> />
)} )}
@ -121,7 +159,7 @@ class TagPage extends React.PureComponent {
title={__('Content from')} title={__('Content from')}
onOverlayPress={() => this.setState({ showTimePicker: false })} onOverlayPress={() => this.setState({ showTimePicker: false })}
onItemSelected={this.handleTimeItemSelected} onItemSelected={this.handleTimeItemSelected}
selectedItem={this.state.currentTimeItem} selectedItem={timeItem}
items={Constants.CLAIM_SEARCH_TIME_ITEMS} items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/> />
)} )}

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { View, ScrollView, Text } from 'react-native'; import { NativeModules, View, ScrollView, Text } from 'react-native';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api 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';
@ -23,6 +23,8 @@ class TransactionHistoryPage extends React.PureComponent {
const { fetchTransactions, pushDrawerStack, setPlayerVisible } = this.props; const { fetchTransactions, pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Transaction History');
fetchTransactions(); fetchTransactions();
}; };

View file

@ -1,18 +1,23 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import { selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
import TrendingPage from './view'; import TrendingPage from './view';
const select = state => ({ const select = state => ({
currentRoute: selectCurrentRoute(state), currentRoute: selectCurrentRoute(state),
sortByItem: selectSortByItem(state),
timeItem: selectTimeItem(state),
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_TRENDING)), pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setSortByItem: item => dispatch(doSetSortByItem(item)),
setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect( export default connect(

View file

@ -1,6 +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 { normalizeURI } from 'lbry-redux';
import { 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';
@ -23,7 +24,10 @@ const TRENDING_FOR_ITEMS = [
class TrendingPage extends React.PureComponent { class TrendingPage extends React.PureComponent {
state = { state = {
showModalTagSelector: false, showModalTagSelector: false,
showSortByPicker: false,
showTimePicker: false,
showTrendingForPicker: false, showTrendingForPicker: false,
orderBy: Constants.DEFAULT_ORDER_BY,
currentTrendingForItem: TRENDING_FOR_ITEMS[0], currentTrendingForItem: TRENDING_FOR_ITEMS[0],
}; };
@ -41,9 +45,12 @@ class TrendingPage extends React.PureComponent {
} }
onComponentFocused = () => { onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible } = this.props; const { pushDrawerStack, setPlayerVisible, navigation } = this.props;
pushDrawerStack(); const { filterForTags } = navigation.state.params ? navigation.state.params : { filterForTags: false };
this.setState({ currentTrendingForItem: TRENDING_FOR_ITEMS[filterForTags ? 1 : 0] });
pushDrawerStack(Constants.DRAWER_ROUTE_TRENDING, navigation.state.params);
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('All content');
}; };
componentDidMount() { componentDidMount() {
@ -62,44 +69,96 @@ class TrendingPage extends React.PureComponent {
this.setState({ currentTrendingForItem: item, showTrendingForPicker: false }); this.setState({ currentTrendingForItem: item, showTrendingForPicker: false });
}; };
handleSortByItemSelected = item => {
const { setSortByItem } = this.props;
setSortByItem(item);
this.setState({ orderBy: getOrderBy(item), showSortPicker: false });
};
handleTimeItemSelected = item => {
const { setTimeItem } = this.props;
setTimeItem(item);
this.setState({ showTimePicker: false });
};
listHeader = () => {
const { sortByItem, timeItem } = this.props;
const { currentTrendingForItem } = this.state;
const sortByTop = Constants.SORT_BY_TOP === sortByItem.name;
return (
<View style={discoverStyle.listHeader}>
<View style={discoverStyle.titleRow}>
<Text style={discoverStyle.pageTitle}>All content</Text>
</View>
<View style={discoverStyle.pickerRow}>
<View style={discoverStyle.leftPickerRow}>
<TouchableOpacity
style={discoverStyle.allTagSortBy}
onPress={() => this.setState({ showSortPicker: true })}
>
<Text style={discoverStyle.tagSortText}>{sortByItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
<Text style={discoverStyle.pickerLabel}>for</Text>
<TouchableOpacity
style={discoverStyle.allTagSortBy}
onPress={() => this.setState({ showTrendingForPicker: true })}
>
<Text style={discoverStyle.tagSortText}>{currentTrendingForItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
{sortByTop && <Text style={discoverStyle.pickerLabel}>in the</Text>}
{sortByTop && (
<TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
<Text style={discoverStyle.tagSortText}>{timeItem.label}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
)}
</View>
{TRENDING_FOR_ITEMS[1].name === currentTrendingForItem.name && (
<Link
style={discoverStyle.customizeLink}
text={'Customize'}
onPress={() => this.setState({ showModalTagSelector: true })}
/>
)}
</View>
</View>
);
};
render() { render() {
const { followedTags, navigation } = this.props; const { followedTags, navigation, sortByItem, timeItem } = this.props;
const { currentTrendingForItem, showModalTagSelector, showTrendingForPicker } = this.state; const {
currentTrendingForItem,
orderBy,
showModalTagSelector,
showSortPicker,
showTimePicker,
showTrendingForPicker,
} = this.state;
const filteredForTags = TRENDING_FOR_ITEMS[1].name === currentTrendingForItem.name;
return ( return (
<View style={discoverStyle.container}> <View style={discoverStyle.container}>
<UriBar navigation={navigation} /> <UriBar navigation={navigation} />
<ClaimList <ClaimList
ListHeaderComponent={ ListHeaderComponent={this.listHeader}
<View style={discoverStyle.titleRow}>
<Text style={discoverStyle.pageTitle}>Trending</Text>
<View style={discoverStyle.rightTitleRow}>
{TRENDING_FOR_ITEMS[1].name === currentTrendingForItem.name && (
<Link
style={discoverStyle.customizeLink}
text={'Customize'}
onPress={() => this.setState({ showModalTagSelector: true })}
/>
)}
<TouchableOpacity
style={discoverStyle.tagSortBy}
onPress={() => this.setState({ showTrendingForPicker: true })}
>
<Text style={discoverStyle.tagSortText}>{currentTrendingForItem.label.split(' ')[0]}</Text>
<Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
</TouchableOpacity>
</View>
</View>
}
style={discoverStyle.verticalClaimList} style={discoverStyle.verticalClaimList}
orderBy={Constants.DEFAULT_ORDER_BY} orderBy={orderBy}
trendingForAll={TRENDING_FOR_ITEMS[0].name === currentTrendingForItem.name} tags={filteredForTags ? followedTags.map(tag => tag.name) : null}
tags={followedTags.map(tag => tag.name)} time={timeItem.name}
time={null}
navigation={navigation} navigation={navigation}
orientation={Constants.ORIENTATION_VERTICAL} orientation={Constants.ORIENTATION_VERTICAL}
/> />
{!showModalTagSelector && <FloatingWalletBalance navigation={navigation} />} {!showModalTagSelector && !showTrendingForPicker && !showSortPicker && !showTimePicker && (
<FloatingWalletBalance navigation={navigation} />
)}
{showModalTagSelector && ( {showModalTagSelector && (
<ModalTagSelector <ModalTagSelector
onOverlayPress={() => this.setState({ showModalTagSelector: false })} onOverlayPress={() => this.setState({ showModalTagSelector: false })}
@ -108,13 +167,31 @@ class TrendingPage extends React.PureComponent {
)} )}
{showTrendingForPicker && ( {showTrendingForPicker && (
<ModalPicker <ModalPicker
title={'Trending for'} title={'Filter for'}
onOverlayPress={() => this.setState({ showTrendingForPicker: false })} onOverlayPress={() => this.setState({ showTrendingForPicker: false })}
onItemSelected={this.handleTrendingForItemSelected} onItemSelected={this.handleTrendingForItemSelected}
selectedItem={currentTrendingForItem} selectedItem={currentTrendingForItem}
items={TRENDING_FOR_ITEMS} items={TRENDING_FOR_ITEMS}
/> />
)} )}
{showSortPicker && (
<ModalPicker
title={__('Sort content by')}
onOverlayPress={() => this.setState({ showSortPicker: false })}
onItemSelected={this.handleSortByItemSelected}
selectedItem={sortByItem}
items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
/>
)}
{showTimePicker && (
<ModalPicker
title={__('Content from')}
onOverlayPress={() => this.setState({ showTimePicker: false })}
onItemSelected={this.handleTimeItemSelected}
selectedItem={timeItem}
items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/>
)}
</View> </View>
); );
} }

View file

@ -29,6 +29,7 @@ class VerificationScreen extends React.PureComponent {
componentDidMount() { componentDidMount() {
const { user } = this.props; const { user } = this.props;
this.checkVerificationStatus(user); this.checkVerificationStatus(user);
NativeModules.Firebase.setCurrentScreen('Verification');
} }
setEmailVerificationPhase = value => { setEmailVerificationPhase = value => {

View file

@ -42,6 +42,7 @@ class WalletPage extends React.PureComponent {
const { pushDrawerStack, setPlayerVisible } = this.props; const { pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Wallet');
const { deviceWalletSynced, getSync, user } = this.props; const { deviceWalletSynced, getSync, user } = this.props;
if (deviceWalletSynced && user && user.has_verified_email) { if (deviceWalletSynced && user && user.has_verified_email) {

View file

@ -27,3 +27,14 @@ export function doSetSortByItem(item) {
}); });
}; };
} }
export function doSetTimeItem(item) {
return dispatch => {
dispatch({
type: Constants.ACTION_TIME_ITEM_CHANGED,
data: {
name: item.name,
},
});
};
}

View file

@ -5,6 +5,7 @@ const reducers = {};
const defaultState = { const defaultState = {
clientSettings: {}, clientSettings: {},
sortByItemName: Constants.SORT_BY_HOT, sortByItemName: Constants.SORT_BY_HOT,
timeItemName: Constants.TIME_WEEK,
}; };
reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => { reducers[ACTIONS.CLIENT_SETTING_CHANGED] = (state, action) => {
@ -23,6 +24,11 @@ reducers[Constants.ACTION_SORT_BY_ITEM_CHANGED] = (state, action) =>
sortByItemName: action.data.name, sortByItemName: action.data.name,
}); });
reducers[Constants.ACTION_TIME_ITEM_CHANGED] = (state, action) =>
Object.assign({}, state, {
timeItemName: 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,6 +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'; import { getSortByItemForName, getTimeItemForName } from 'utils/helper';
const selectState = state => state.settings || {}; const selectState = state => state.settings || {};
@ -19,6 +19,11 @@ export const selectSortByItem = createSelector(
state => getSortByItemForName(state.sortByItemName) state => getSortByItemForName(state.sortByItemName)
); );
export const selectTimeItem = createSelector(
selectState,
state => getTimeItemForName(state.timeItemName)
);
export const makeSelectClientSetting = setting => export const makeSelectClientSetting = setting =>
createSelector( createSelector(
selectClientSettings, selectClientSettings,

View file

@ -33,7 +33,7 @@ const buttonStyle = StyleSheet.create({
fontSize: 14, fontSize: 14,
}, },
textWithIcon: { textWithIcon: {
marginLeft: 8, marginLeft: 4,
}, },
}); });

View file

@ -31,13 +31,11 @@ const channelPageStyle = StyleSheet.create({
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
flexDirection: 'row',
}, },
infoText: { infoText: {
fontFamily: 'Inter-UI-Regular', fontFamily: 'Inter-UI-Regular',
fontSize: 20, fontSize: 20,
textAlign: 'center', textAlign: 'center',
marginLeft: 10,
}, },
pageButtons: { pageButtons: {
width: '100%', width: '100%',
@ -69,7 +67,7 @@ const channelPageStyle = StyleSheet.create({
subscribeButtonContainer: { subscribeButtonContainer: {
position: 'absolute', position: 'absolute',
flexDirection: 'row', flexDirection: 'row',
left: 8, right: 8,
bottom: -90, bottom: -90,
zIndex: 100, zIndex: 100,
}, },
@ -148,11 +146,25 @@ const channelPageStyle = StyleSheet.create({
left: 24, left: 24,
bottom: -40, bottom: -40,
zIndex: 100, zIndex: 100,
alignItems: 'center',
justifyContent: 'center',
}, },
avatarImage: { avatarImage: {
width: '100%', width: '100%',
height: '100%', height: '100%',
}, },
listHeader: {
marginTop: 16,
marginBottom: 8,
marginLeft: 16,
marginRight: 16,
},
claimList: {
flex: 1,
},
claimListContent: {
paddingTop: 16,
},
}); });
export default channelPageStyle; export default channelPageStyle;

View file

@ -28,16 +28,25 @@ const discoverStyle = StyleSheet.create({
scrollContainer: { scrollContainer: {
flex: 1, flex: 1,
}, },
listHeader: {
marginBottom: 8,
marginLeft: 16,
marginRight: 16,
},
titleRow: { titleRow: {
flexDirection: 'row', flexDirection: 'row',
marginTop: 76, marginTop: 76,
marginBottom: 8, marginBottom: 8,
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
marginLeft: 16,
marginRight: 16,
}, },
rightTitleRow: { pickerRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 8,
},
leftPickerRow: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
}, },
@ -48,7 +57,6 @@ const discoverStyle = StyleSheet.create({
customizeLink: { customizeLink: {
fontFamily: 'Inter-UI-Regular', fontFamily: 'Inter-UI-Regular',
fontSize: 14, fontSize: 14,
marginRight: 48,
}, },
trendingContainer: { trendingContainer: {
flex: 1, flex: 1,
@ -258,7 +266,12 @@ const discoverStyle = StyleSheet.create({
tagSortBy: { tagSortBy: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
marginRight: 4, marginRight: 24,
},
allTagSortBy: {
flexDirection: 'row',
alignItems: 'center',
marginRight: 8,
}, },
tagTime: { tagTime: {
flexDirection: 'row', flexDirection: 'row',
@ -272,6 +285,53 @@ const discoverStyle = StyleSheet.create({
tagSortIcon: { tagSortIcon: {
marginTop: -6, marginTop: -6,
}, },
pickerLabel: {
fontFamily: 'Inter-UI-Regular',
fontSize: 14,
color: Colors.DescriptionGrey,
marginRight: 6,
},
menuScrollContent: {
paddingTop: 16,
},
menuGroup: {
marginTop: 8,
marginBottom: 8,
},
menuGroupName: {
fontFamily: 'Inter-UI-Regular',
fontSize: 12,
color: Colors.DescriptionGrey,
textTransform: 'uppercase',
marginBottom: 4,
marginLeft: 16,
marginRight: 16,
},
menuItemTouchArea: {
flex: 1,
flexDirection: 'row',
paddingTop: 12,
paddingBottom: 12,
paddingLeft: 16,
paddingRight: 16,
alignItems: 'center',
},
menuItemTouchAreaFocused: {
backgroundColor: Colors.VeryLightGrey,
},
menuItemFocused: {
color: Colors.LbryGreen,
},
menuItemIcon: {
alignItems: 'center',
justifyContent: 'center',
width: 24,
},
menuItem: {
marginLeft: 8,
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
},
}); });
export default discoverStyle; export default discoverStyle;

View file

@ -341,6 +341,11 @@ const publishStyle = StyleSheet.create({
fontSize: 14, fontSize: 14,
marginLeft: 8, marginLeft: 8,
}, },
relativeCentered: {
alignItems: 'center',
justifyContent: 'center',
padding: 16,
},
centered: { centered: {
position: 'absolute', position: 'absolute',
left: 0, left: 0,

View file

@ -156,10 +156,18 @@ const subscriptionsStyle = StyleSheet.create({
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
}, },
pickerRow: {
flexDirection: 'row',
alignItems: 'center',
marginLeft: 16,
marginRight: 16,
marginTop: 8,
marginBottom: 8,
},
tagSortBy: { tagSortBy: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
marginRight: 4, marginRight: 24,
}, },
tagSortText: { tagSortText: {
fontFamily: 'Inter-UI-Regular', fontFamily: 'Inter-UI-Regular',

View file

@ -217,6 +217,16 @@ export function getSortByItemForName(name) {
return null; return null;
} }
export function getTimeItemForName(name) {
for (let i = 0; i < Constants.CLAIM_SEARCH_TIME_ITEMS.length; i++) {
if (name === Constants.CLAIM_SEARCH_TIME_ITEMS[i].name) {
return Constants.CLAIM_SEARCH_TIME_ITEMS[i];
}
}
return null;
}
export function getOrderBy(item) { export function getOrderBy(item) {
let orderBy = []; let orderBy = [];
switch (item.name) { switch (item.name) {