Editor's Choice page

This commit is contained in:
Akinwale Ariwodola 2020-04-01 15:59:37 +01:00
parent aa5dd878c0
commit f16d068a7d
10 changed files with 258 additions and 5 deletions

@ -1 +1 @@
Subproject commit ff30e7f6a4358fd997a9e6d9f75bfe6959eafcb6
Subproject commit cc3055f1c98c4dd5e5bbccdd9d4a39a5a37fdf82

View file

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

View file

@ -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}

View file

@ -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 },
],

View 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);

View 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;

View file

@ -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',

View 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);

View 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;

View 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;