Editor's Choice page
This commit is contained in:
parent
aa5dd878c0
commit
f16d068a7d
10 changed files with 258 additions and 5 deletions
2
android
2
android
|
@ -1 +1 @@
|
|||
Subproject commit ff30e7f6a4358fd997a9e6d9f75bfe6959eafcb6
|
||||
Subproject commit cc3055f1c98c4dd5e5bbccdd9d4a39a5a37fdf82
|
|
@ -4,6 +4,7 @@ import ChannelCreatorPage from 'page/channelCreator';
|
|||
import DiscoverPage from 'page/discover';
|
||||
import DownloadsPage from 'page/downloads';
|
||||
import DrawerContent from 'component/drawerContent';
|
||||
import EditorsChoicePage from 'page/editorsChoice';
|
||||
import FilePage from 'page/file';
|
||||
import LiteFilePage from 'page/liteFile';
|
||||
import FirstRunScreen from 'page/firstRun';
|
||||
|
@ -164,6 +165,13 @@ const drawer = createDrawerNavigator(
|
|||
drawerIcon: ({ tintColor }) => <Icon name="home" size={drawerIconSize} style={{ color: tintColor }} />,
|
||||
},
|
||||
},
|
||||
EditorsChoice: {
|
||||
screen: EditorsChoicePage,
|
||||
navigationOptions: {
|
||||
title: "Editor's Choice",
|
||||
drawerIcon: ({ tintColor }) => <Icon name="star" size={drawerIconSize} style={{ color: tintColor }} />,
|
||||
},
|
||||
},
|
||||
Discover: {
|
||||
screen: DiscoverPage,
|
||||
navigationOptions: ({ navigation }) => ({
|
||||
|
|
|
@ -3,6 +3,7 @@ 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 EditorsChoiceItem from 'component/editorsChoiceItem';
|
||||
import FileItem from 'component/fileItem';
|
||||
import FileListItem from 'component/fileListItem';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
|
@ -72,7 +73,7 @@ class ClaimList extends React.PureComponent {
|
|||
|
||||
buildClaimSearchOptions() {
|
||||
const { orderBy, channelIds, showNsfwContent, tags, time } = this.props;
|
||||
const { currentPage, subscriptionsView } = this.state;
|
||||
const { currentPage } = this.state;
|
||||
|
||||
const options = {
|
||||
order_by: orderBy,
|
||||
|
@ -101,7 +102,7 @@ class ClaimList extends React.PureComponent {
|
|||
return `>${Math.floor(
|
||||
moment()
|
||||
.subtract(1, time)
|
||||
.unix()
|
||||
.unix(),
|
||||
)}`;
|
||||
};
|
||||
|
||||
|
@ -120,7 +121,7 @@ class ClaimList extends React.PureComponent {
|
|||
const uris = claimSearchByQuery[claimSearchKey];
|
||||
if (
|
||||
lastPageReached[claimSearchKey] ||
|
||||
((uris.length > 0 && uris.length < Constants.DEFAULT_PAGE_SIZE) || uris.length >= softLimit)
|
||||
(uris.length > 0 && uris.length < Constants.DEFAULT_PAGE_SIZE) || uris.length >= softLimit
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -174,6 +175,12 @@ class ClaimList extends React.PureComponent {
|
|||
);
|
||||
};
|
||||
|
||||
renderEditorsChoiceItem = ({ item }) => {
|
||||
const { navigation } = this.props;
|
||||
|
||||
return <EditorsChoiceItem style={discoverStyle.fileItem} key={item} uri={normalizeURI(item)} />;
|
||||
};
|
||||
|
||||
renderHorizontalItem = ({ item }) => {
|
||||
const { navigation } = this.props;
|
||||
|
||||
|
@ -195,6 +202,7 @@ class ClaimList extends React.PureComponent {
|
|||
render() {
|
||||
const {
|
||||
ListHeaderComponent,
|
||||
editorsChoice,
|
||||
loading,
|
||||
morePlaceholder,
|
||||
navigation,
|
||||
|
@ -226,7 +234,7 @@ class ClaimList extends React.PureComponent {
|
|||
initialNumToRender={10}
|
||||
maxToRenderPerBatch={20}
|
||||
removeClippedSubviews
|
||||
renderItem={this.renderVerticalItem}
|
||||
renderItem={editorsChoice ? this.renderEditorsChoiceItem : this.renderVerticalItem}
|
||||
data={uris}
|
||||
keyExtractor={(item, index) => item}
|
||||
onEndReached={this.handleVerticalEndReached}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { formatUsd } from 'utils/helper';
|
|||
const groupedMenuItems = {
|
||||
'Find content': [
|
||||
{ icon: 'heart', solid: true, label: 'Following', route: Constants.DRAWER_ROUTE_SUBSCRIPTIONS },
|
||||
{ icon: 'star', solid: true, label: "Editor's Choice", route: Constants.DRAWER_ROUTE_EDITORS_CHOICE },
|
||||
{ icon: 'hashtag', label: 'Your Tags', route: Constants.DRAWER_ROUTE_DISCOVER },
|
||||
{ icon: 'globe-americas', label: 'All Content', route: Constants.DRAWER_ROUTE_TRENDING },
|
||||
],
|
||||
|
|
22
src/component/editorsChoiceItem/index.js
Normal file
22
src/component/editorsChoiceItem/index.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
doResolveUri,
|
||||
makeSelectClaimForUri,
|
||||
makeSelectMetadataForUri,
|
||||
makeSelectTitleForUri,
|
||||
makeSelectThumbnailForUri,
|
||||
} from 'lbry-redux';
|
||||
import EditorsChoiceItem from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
metadata: makeSelectMetadataForUri(props.uri)(state),
|
||||
title: makeSelectTitleForUri(props.uri)(state),
|
||||
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(EditorsChoiceItem);
|
63
src/component/editorsChoiceItem/view.js
Normal file
63
src/component/editorsChoiceItem/view.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
import React from 'react';
|
||||
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||
import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { navigateToUri } from 'utils/helper';
|
||||
import Colors from 'styles/colors';
|
||||
import ChannelIconItem from 'component/channelIconItem';
|
||||
import channelIconStyle from 'styles/channelIcon';
|
||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||
import DateTime from 'component/dateTime';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import FileItemMedia from 'component/fileItemMedia';
|
||||
import FilePrice from 'component/filePrice';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
import Link from 'component/link';
|
||||
import NsfwOverlay from 'component/nsfwOverlay';
|
||||
import ProgressBar from 'component/progressBar';
|
||||
import editorsChoiceStyle from 'styles/editorsChoice';
|
||||
|
||||
class EditorsChoiceItem extends React.PureComponent {
|
||||
componentDidMount() {
|
||||
const { claim, resolveUri, uri, batchResolve } = this.props;
|
||||
if (!claim && !batchResolve) {
|
||||
resolveUri(uri);
|
||||
}
|
||||
}
|
||||
|
||||
defaultOnPress = () => {
|
||||
const { autoplay, claim, navigation, uri } = this.props;
|
||||
navigateToUri(navigation, uri, { autoplay }, false, claim ? claim.permanent_url : null);
|
||||
};
|
||||
|
||||
onPressHandler = () => {
|
||||
const { claim, onPress } = this.props;
|
||||
if (onPress) {
|
||||
onPress(claim);
|
||||
} else {
|
||||
this.defaultOnPress();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { metadata, title, thumbnail } = this.props;
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={editorsChoiceStyle.item}>
|
||||
<FastImage
|
||||
style={editorsChoiceStyle.thumbnail}
|
||||
resizeMode={FastImage.resizeMode.cover}
|
||||
source={{ uri: thumbnail }}
|
||||
/>
|
||||
|
||||
<View style={editorsChoiceStyle.detailsContainer}>
|
||||
<Text style={editorsChoiceStyle.title}>{title}</Text>
|
||||
<Text style={editorsChoiceStyle.description}>
|
||||
{metadata.description ? metadata.description.substring(0, 400) : __('No description available')}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditorsChoiceItem;
|
|
@ -81,6 +81,7 @@ const Constants = {
|
|||
PAGE_WALLET: 'wallet',
|
||||
|
||||
DRAWER_ROUTE_DISCOVER: 'Discover',
|
||||
DRAWER_ROUTE_EDITORS_CHOICE: 'EditorsChoice',
|
||||
DRAWER_ROUTE_TRENDING: 'Trending',
|
||||
DRAWER_ROUTE_SUBSCRIPTIONS: 'Subscriptions',
|
||||
DRAWER_ROUTE_MY_LBRY: 'Downloads',
|
||||
|
|
16
src/page/editorsChoice/index.js
Normal file
16
src/page/editorsChoice/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||
import { selectCurrentRoute } from 'redux/selectors/drawer';
|
||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||
import EditorsChoicePage from './view';
|
||||
|
||||
const select = state => ({
|
||||
currentRoute: selectCurrentRoute(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_EDITORS_CHOICE)),
|
||||
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(EditorsChoicePage);
|
90
src/page/editorsChoice/view.js
Normal file
90
src/page/editorsChoice/view.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
import React from 'react';
|
||||
import { ActivityIndicator, NativeModules, FlatList, Text, TouchableOpacity, ScrollView, View } from 'react-native';
|
||||
import { DEFAULT_FOLLOWED_TAGS, normalizeURI } from 'lbry-redux';
|
||||
import { formatTagTitle, getOrderBy } from 'utils/helper';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import moment from 'moment';
|
||||
import ClaimList from 'component/claimList';
|
||||
import FileItem from 'component/fileItem';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
import discoverStyle from 'styles/discover';
|
||||
import fileListStyle from 'styles/fileList';
|
||||
import Colors from 'styles/colors';
|
||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||
import Link from 'component/link';
|
||||
import ModalPicker from 'component/modalPicker';
|
||||
import SdkLoadingStatus from 'component/sdkLoadingStatus';
|
||||
import UriBar from 'component/uriBar';
|
||||
import editorsChoiceStyle from 'styles/editorsChoice';
|
||||
|
||||
class EditorsChoicePage extends React.PureComponent {
|
||||
onComponentFocused = () => {
|
||||
const { pushDrawerStack, setPlayerVisible } = this.props;
|
||||
pushDrawerStack();
|
||||
setPlayerVisible();
|
||||
NativeModules.Firebase.setCurrentScreen('EditorsChoice');
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.onComponentFocused();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { currentRoute } = nextProps;
|
||||
const { currentRoute: prevRoute } = this.props;
|
||||
if (Constants.DRAWER_ROUTE_EDITORS_CHOICE === currentRoute && currentRoute !== prevRoute) {
|
||||
this.onComponentFocused();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
|
||||
return (
|
||||
<View style={editorsChoiceStyle.container}>
|
||||
<UriBar navigation={navigation} />
|
||||
|
||||
<ScrollView style={editorsChoiceStyle.categories} contentContainerStyle={editorsChoiceStyle.categoriesContent}>
|
||||
<Text style={editorsChoiceStyle.category}>{__('Short Films')}</Text>
|
||||
<ClaimList
|
||||
style={editorsChoiceStyle.claimList}
|
||||
channelIds={['7056f8267188fc49cd3f7162b4115d9e3c8216f6']}
|
||||
editorsChoice
|
||||
navigation={navigation}
|
||||
orientation={Constants.ORIENTATION_VERTICAL}
|
||||
/>
|
||||
|
||||
<Text style={editorsChoiceStyle.category}>{__('Feature-Length Films')}</Text>
|
||||
<ClaimList
|
||||
style={editorsChoiceStyle.claimList}
|
||||
channelIds={['7aad6f36f61da95cb02471fae55f736b28e3bca7']}
|
||||
editorsChoice
|
||||
navigation={navigation}
|
||||
orientation={Constants.ORIENTATION_VERTICAL}
|
||||
/>
|
||||
|
||||
<Text style={editorsChoiceStyle.category}>{__('Documentaries')}</Text>
|
||||
<ClaimList
|
||||
style={editorsChoiceStyle.claimList}
|
||||
channelIds={['d57c606e11462e821d5596430c336b58716193bb']}
|
||||
editorsChoice
|
||||
navigation={navigation}
|
||||
orientation={Constants.ORIENTATION_VERTICAL}
|
||||
/>
|
||||
|
||||
<Text style={editorsChoiceStyle.category}>{__('Episodic Content')}</Text>
|
||||
<ClaimList
|
||||
style={editorsChoiceStyle.claimList}
|
||||
channelIds={['ea5fc1bd3e1335776fe2641a539a47850606d7db']}
|
||||
editorsChoice
|
||||
navigation={navigation}
|
||||
orientation={Constants.ORIENTATION_VERTICAL}
|
||||
/>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditorsChoicePage;
|
44
src/styles/editorsChoice.js
Normal file
44
src/styles/editorsChoice.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
import Colors from './colors';
|
||||
|
||||
const editorsChoiceStyle = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.PageBackground,
|
||||
},
|
||||
categories: {
|
||||
marginTop: 60,
|
||||
},
|
||||
categoriesContent: {
|
||||
padding: 16,
|
||||
},
|
||||
item: {
|
||||
flex: 1,
|
||||
marginTop: 8,
|
||||
},
|
||||
category: {
|
||||
fontFamily: 'Inter-SemiBold',
|
||||
fontSize: 24,
|
||||
color: Colors.LbryGreen,
|
||||
marginBottom: 4,
|
||||
},
|
||||
thumbnail: {
|
||||
width: '100%',
|
||||
height: 240,
|
||||
},
|
||||
detailsContainer: {
|
||||
marginLeft: 8,
|
||||
},
|
||||
title: {
|
||||
fontFamily: 'Inter-SemiBold',
|
||||
fontSize: 18,
|
||||
marginTop: 8,
|
||||
},
|
||||
description: {
|
||||
fontFamily: 'Inter-Regular',
|
||||
fontSize: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
});
|
||||
|
||||
export default editorsChoiceStyle;
|
Loading…
Reference in a new issue