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
5 changed files with 100 additions and 96 deletions
Showing only changes of commit 84dda42a56 - Show all commits

View file

@ -161,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 }) => {

View file

@ -1,7 +1,7 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import { formatBigNumberCredits } from 'lbry-redux'; import { formatCredits } from 'lbry-redux';
import Address from 'component/address'; import Address from 'component/address';
import Button from 'component/button'; import Button from 'component/button';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
@ -34,7 +34,7 @@ class FloatingWalletBalance extends React.PureComponent<Props> {
<Icon name="coins" size={12} style={floatingButtonStyle.balanceIcon} /> <Icon name="coins" size={12} style={floatingButtonStyle.balanceIcon} />
{isNaN(balance) && <ActivityIndicator size="small" color={Colors.White} />} {isNaN(balance) && <ActivityIndicator size="small" color={Colors.White} />}
{(!isNaN(balance) || balance === 0) && ( {(!isNaN(balance) || balance === 0) && (
<Text style={floatingButtonStyle.text}>{formatBigNumberCredits(parseFloat(balance), 0)}</Text> <Text style={floatingButtonStyle.text}>{formatCredits(parseFloat(balance), 0, true)}</Text>
)} )}
</TouchableOpacity> </TouchableOpacity>
</View> </View>

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

@ -3,111 +3,86 @@ import React from 'react';
import { ActivityIndicator, Dimensions, Image, ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Dimensions, Image, 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 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 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, showSortPicker: false,
showPageButtons: false, showTimePicker: false,
orderBy: Constants.DEFAULT_ORDER_BY,
activeTab: Constants.CONTENT_TAB, activeTab: Constants.CONTENT_TAB,
}; };
componentDidMount() { handleSortByItemSelected = item => {
const { uri, page, claimsInChannel, fetchClaims, fetchClaimCount } = this.props; const { setSortByItem } = this.props;
setSortByItem(item);
if (!claimsInChannel || !claimsInChannel.length) { this.setState({ orderBy: getOrderBy(item), showSortPicker: false });
fetchClaims(uri, page || this.state.page);
}
}
handlePreviousPage = () => {
const { uri, fetchClaims } = this.props;
if (this.state.page > 1) {
this.setState({ page: this.state.page - 1, showPageButtons: false }, () => {
fetchClaims(uri, this.state.page);
});
}
}; };
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={discoverStyle.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,8 +137,9 @@ 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 { showSortPicker, showTimePicker } = this.state;
let thumbnailUrl, coverUrl, title, fullUri; let thumbnailUrl, coverUrl, title, fullUri;
if (claim) { if (claim) {
@ -242,6 +218,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

@ -69,7 +69,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,
}, },
@ -153,6 +153,10 @@ const channelPageStyle = StyleSheet.create({
width: '100%', width: '100%',
height: '100%', height: '100%',
}, },
claimList: {
flex: 1,
marginTop: 16,
},
}); });
export default channelPageStyle; export default channelPageStyle;