271 lines
7.7 KiB
JavaScript
271 lines
7.7 KiB
JavaScript
import React from 'react';
|
|
import NavigationActions from 'react-navigation';
|
|
import { ActivityIndicator, FlatList, Text, TouchableOpacity, View } from 'react-native';
|
|
import { MATURE_TAGS, normalizeURI, createNormalizedClaimSearchKey } from 'lbry-redux';
|
|
import _ from 'lodash';
|
|
import FileItem from 'component/fileItem';
|
|
import FileListItem from 'component/fileListItem';
|
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
|
import Colors from 'styles/colors';
|
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
|
import claimListStyle from 'styles/claimList';
|
|
import discoverStyle from 'styles/discover';
|
|
import moment from 'moment';
|
|
|
|
const horizontalLimit = 7;
|
|
const softLimit = 500;
|
|
|
|
class ClaimList extends React.PureComponent {
|
|
scrollView = null;
|
|
|
|
state = {
|
|
currentPage: 1, // initial page load is page 1
|
|
subscriptionsView: false, // whether or not this claim list is for subscriptions
|
|
lastPageReached: false,
|
|
};
|
|
|
|
componentDidMount() {
|
|
const { channelIds } = this.props;
|
|
|
|
if (channelIds) {
|
|
this.setState({ subscriptionsView: true });
|
|
}
|
|
|
|
this.doClaimSearch();
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
const {
|
|
claimSearchByQuery: prevClaimSearchByQuery,
|
|
orderBy: prevOrderBy,
|
|
searchByTags,
|
|
tags: prevTags,
|
|
channelIds: prevChannelIds,
|
|
time: prevTime,
|
|
} = prevProps;
|
|
const { claimSearchByQuery, orderBy, tags, channelIds, time } = this.props;
|
|
|
|
if (
|
|
!_.isEqual(orderBy, prevOrderBy) ||
|
|
!_.isEqual(tags, prevTags) ||
|
|
!_.isEqual(channelIds, prevChannelIds) ||
|
|
time !== prevTime
|
|
) {
|
|
// reset to page 1 because the order, tags or channelIds changed
|
|
this.setState({ currentPage: 1 }, () => {
|
|
if (this.scrollView) {
|
|
this.scrollView.scrollToOffset({ animated: true, offset: 0 });
|
|
}
|
|
|
|
if (prevChannelIds && channelIds) {
|
|
if (channelIds) {
|
|
this.setState({ subscriptionsView: true });
|
|
}
|
|
} else if (tags && tags.length > 0) {
|
|
this.setState({ subscriptionsView: false });
|
|
}
|
|
|
|
this.doClaimSearch();
|
|
});
|
|
}
|
|
}
|
|
|
|
buildClaimSearchOptions() {
|
|
const { orderBy, channelIds, showNsfwContent, tags, time } = this.props;
|
|
const { currentPage, subscriptionsView } = this.state;
|
|
|
|
const options = {
|
|
order_by: orderBy,
|
|
no_totals: true,
|
|
page: currentPage,
|
|
page_size: Constants.DEFAULT_PAGE_SIZE,
|
|
};
|
|
|
|
if (channelIds) {
|
|
options.channel_ids = channelIds;
|
|
} else if (tags && tags.length > 0) {
|
|
options.any_tags = tags;
|
|
}
|
|
if (!showNsfwContent) {
|
|
options.not_tags = MATURE_TAGS;
|
|
}
|
|
|
|
if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
|
|
options.release_time = this.getReleaseTimeOption(time);
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
getReleaseTimeOption = time => {
|
|
return `>${Math.floor(
|
|
moment()
|
|
.subtract(1, time)
|
|
.unix()
|
|
)}`;
|
|
};
|
|
|
|
doClaimSearch() {
|
|
const { claimSearch } = this.props;
|
|
const options = this.buildClaimSearchOptions();
|
|
claimSearch(options);
|
|
}
|
|
|
|
handleVerticalEndReached = () => {
|
|
// fetch more content
|
|
const { claimSearchByQuery, lastPageReached } = this.props;
|
|
|
|
const options = this.buildClaimSearchOptions();
|
|
const claimSearchKey = createNormalizedClaimSearchKey(options);
|
|
const uris = claimSearchByQuery[claimSearchKey];
|
|
if (
|
|
lastPageReached[claimSearchKey] ||
|
|
((uris.length > 0 && uris.length < Constants.DEFAULT_PAGE_SIZE) || uris.length >= softLimit)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
this.setState({ currentPage: this.state.currentPage + 1 }, () => this.doClaimSearch());
|
|
};
|
|
|
|
appendMorePlaceholder = items => {
|
|
items.push(Constants.MORE_PLACEHOLDER);
|
|
return items;
|
|
};
|
|
|
|
onMorePressed = () => {
|
|
const { navigation, tags } = this.props;
|
|
|
|
// tags.length > 1 means this is the Trending list
|
|
if (tags.length === 1) {
|
|
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: 'tagPage', params: { tag: tags[0] } });
|
|
} else {
|
|
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TRENDING, params: { filterForTags: true } });
|
|
}
|
|
};
|
|
|
|
renderMorePlaceholder = () => {
|
|
return (
|
|
<TouchableOpacity style={discoverStyle.fileItemMore} onPress={this.onMorePressed}>
|
|
<Text style={discoverStyle.moreText}>more</Text>
|
|
<Icon style={discoverStyle.moreIcon} name={'angle-double-down'} color={Colors.White} size={16} />
|
|
</TouchableOpacity>
|
|
);
|
|
};
|
|
|
|
verticalListEmptyComponent = () => {
|
|
return (
|
|
<Text style={claimListStyle.noContentText}>No content to display at this time. Please check back later.</Text>
|
|
);
|
|
};
|
|
|
|
renderVerticalItem = ({ item }) => {
|
|
const { hideChannel, navigation } = this.props;
|
|
return (
|
|
<FileListItem
|
|
key={item}
|
|
uri={item}
|
|
hideChannel={hideChannel}
|
|
style={claimListStyle.verticalListItem}
|
|
navigation={navigation}
|
|
/>
|
|
);
|
|
};
|
|
|
|
renderHorizontalItem = ({ item }) => {
|
|
const { navigation } = this.props;
|
|
|
|
return item === Constants.MORE_PLACEHOLDER ? (
|
|
this.renderMorePlaceholder()
|
|
) : (
|
|
<FileItem
|
|
style={discoverStyle.fileItem}
|
|
mediaStyle={discoverStyle.fileItemMedia}
|
|
key={item}
|
|
uri={normalizeURI(item)}
|
|
navigation={navigation}
|
|
showDetails
|
|
compactView={false}
|
|
/>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
ListHeaderComponent,
|
|
loading,
|
|
morePlaceholder,
|
|
navigation,
|
|
orientation = Constants.ORIENTATION_VERTICAL,
|
|
style,
|
|
claimSearchByQuery,
|
|
} = this.props;
|
|
const { subscriptionsView } = this.state;
|
|
|
|
const options = this.buildClaimSearchOptions();
|
|
const claimSearchKey = createNormalizedClaimSearchKey(options);
|
|
let uris = claimSearchByQuery[claimSearchKey];
|
|
|
|
if (uris) {
|
|
uris = uris.filter(uri => uri && uri.length > 0);
|
|
}
|
|
|
|
if (Constants.ORIENTATION_VERTICAL === orientation) {
|
|
return (
|
|
<View style={style}>
|
|
<FlatList
|
|
ref={ref => {
|
|
this.scrollView = ref;
|
|
}}
|
|
ListHeaderComponent={ListHeaderComponent}
|
|
ListEmptyComponent={loading ? null : this.verticalListEmptyComponent}
|
|
style={claimListStyle.verticalScrollContainer}
|
|
contentContainerStyle={claimListStyle.verticalScrollPadding}
|
|
initialNumToRender={10}
|
|
maxToRenderPerBatch={20}
|
|
removeClippedSubviews
|
|
renderItem={this.renderVerticalItem}
|
|
data={uris}
|
|
keyExtractor={(item, index) => item}
|
|
onEndReached={this.handleVerticalEndReached}
|
|
onEndReachedThreshold={0.2}
|
|
/>
|
|
{loading && (
|
|
<View style={claimListStyle.verticalLoading}>
|
|
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
if (Constants.ORIENTATION_HORIZONTAL === orientation) {
|
|
if (loading) {
|
|
return (
|
|
<View style={discoverStyle.listLoading}>
|
|
<ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<FlatList
|
|
style={style || claimListStyle.horizontalScrollContainer}
|
|
contentContainerStyle={claimListStyle.horizontalScrollPadding}
|
|
initialNumToRender={3}
|
|
maxToRenderPerBatch={3}
|
|
removeClippedSubviews
|
|
renderItem={this.renderHorizontalItem}
|
|
horizontal
|
|
showsHorizontalScrollIndicator={false}
|
|
data={uris ? this.appendMorePlaceholder(uris.slice(0, horizontalLimit)) : []}
|
|
keyExtractor={(item, index) => item}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export default ClaimList;
|