From 7f6874b791bf649e06e3279ce2f9f666f994464e Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 8 Feb 2019 16:48:35 +0100 Subject: [PATCH] Suggested subscriptions (#423) * suggested subscriptions implementation * some style and loading tweaks * add subscribe buttons and style tweaks --- app/src/component/fileItem/view.js | 33 ++++++--- app/src/component/fileList/view.js | 8 +- app/src/component/fileListItem/index.js | 2 +- .../suggestedSubscriptionItem/index.js | 25 +++++++ .../suggestedSubscriptionItem/view.js | 74 +++++++++++++++++++ .../component/suggestedSubscriptions/index.js | 13 ++++ .../component/suggestedSubscriptions/view.js | 52 +++++++++++++ app/src/page/discover/view.js | 16 ++-- app/src/page/subscriptions/index.js | 7 +- app/src/page/subscriptions/view.js | 12 ++- app/src/page/trending/view.js | 14 ++-- app/src/styles/discover.js | 14 ++-- app/src/styles/subscriptions.js | 62 +++++++++++++++- 13 files changed, 285 insertions(+), 47 deletions(-) create mode 100644 app/src/component/suggestedSubscriptionItem/index.js create mode 100644 app/src/component/suggestedSubscriptionItem/view.js create mode 100644 app/src/component/suggestedSubscriptions/index.js create mode 100644 app/src/component/suggestedSubscriptions/view.js diff --git a/app/src/component/fileItem/view.js b/app/src/component/fileItem/view.js index e37d057..1b28aea 100644 --- a/app/src/component/fileItem/view.js +++ b/app/src/component/fileItem/view.js @@ -33,6 +33,15 @@ class FileItem extends React.PureComponent { } } + navigateToFileUri = () => { + const { navigation, uri } = this.props; + const normalizedUri = normalizeURI(uri); + if (NativeModules.Mixpanel) { + NativeModules.Mixpanel.track('Discover Tap', { Uri: normalizeURI }); + } + navigateToUri(navigation, normalizedUri); + } + render() { const { claim, @@ -42,7 +51,10 @@ class FileItem extends React.PureComponent { rewardedContentClaimIds, style, mediaStyle, - navigation + navigation, + showDetails, + compactView, + titleBeforeThumbnail } = this.props; const uri = normalizeURI(this.props.uri); @@ -55,24 +67,21 @@ class FileItem extends React.PureComponent { return ( - { - if (NativeModules.Mixpanel) { - NativeModules.Mixpanel.track('Discover Tap', { Uri: uri }); - } - navigateToUri(navigation, uri); - } - }> + + {!compactView && titleBeforeThumbnail && {title}} - - + + {!compactView && } + {!compactView && {title} {isRewardContent && } - + } + {(!compactView && showDetails) && {channelName && { @@ -80,7 +89,7 @@ class FileItem extends React.PureComponent { navigateToUri(navigation, channelUri); }} />} - + } {obscureNsfw && navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />} diff --git a/app/src/component/fileList/view.js b/app/src/component/fileList/view.js index 4416f7b..cb675ab 100644 --- a/app/src/component/fileList/view.js +++ b/app/src/component/fileList/view.js @@ -2,8 +2,8 @@ import * as React from 'react'; import { buildURI } from 'lbry-redux'; import { FlatList } from 'react-native'; -import FileItem from '../fileItem'; -import discoverStyle from '../../styles/discover'; +import FileItem from 'component/fileItem'; +import discoverStyle from 'styles/discover'; // In the future, all Flow types need to be specified in a common source (lbry-redux, perhaps?) type FileInfo = { @@ -175,7 +175,9 @@ class FileList extends React.PureComponent { renderItem={({item}) => ( + navigation={navigation} + showDetails={true} + compactView={false} /> )} /> ); } diff --git a/app/src/component/fileListItem/index.js b/app/src/component/fileListItem/index.js index f88b911..af81142 100644 --- a/app/src/component/fileListItem/index.js +++ b/app/src/component/fileListItem/index.js @@ -6,7 +6,7 @@ import { makeSelectFileInfoForUri, makeSelectIsUriResolving, } from 'lbry-redux'; -import { selectShowNsfw } from '../../redux/selectors/settings'; +import { selectShowNsfw } from 'redux/selectors/settings'; import FileListItem from './view'; const select = (state, props) => ({ diff --git a/app/src/component/suggestedSubscriptionItem/index.js b/app/src/component/suggestedSubscriptionItem/index.js new file mode 100644 index 0000000..39b6a1c --- /dev/null +++ b/app/src/component/suggestedSubscriptionItem/index.js @@ -0,0 +1,25 @@ +import { connect } from 'react-redux'; +import { + makeSelectFetchingChannelClaims, + makeSelectClaimsInChannelForPage, + doFetchClaimsByChannel, + doResolveUris, +} from 'lbry-redux'; +import { selectShowNsfw } from 'redux/selectors/settings'; +import SuggestedSubscriptionItem from './view'; + +const select = (state, props) => ({ + claims: makeSelectClaimsInChannelForPage(props.categoryLink)(state), + fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state), + obscureNsfw: !selectShowNsfw(state), +}); + +const perform = dispatch => ({ + fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)), + resolveUris: uris => dispatch(doResolveUris(uris, true)), +}); + +export default connect( + select, + perform +)(SuggestedSubscriptionItem); diff --git a/app/src/component/suggestedSubscriptionItem/view.js b/app/src/component/suggestedSubscriptionItem/view.js new file mode 100644 index 0000000..86a6187 --- /dev/null +++ b/app/src/component/suggestedSubscriptionItem/view.js @@ -0,0 +1,74 @@ +import React from 'react'; +import { buildURI, normalizeURI } from 'lbry-redux'; +import { ActivityIndicator, FlatList, Text, View } from 'react-native'; +import Colors from 'styles/colors'; +import discoverStyle from 'styles/discover'; +import FileItem from 'component/fileItem'; +import subscriptionsStyle from 'styles/subscriptions'; + +class SuggestedSubscriptionItem extends React.PureComponent { + componentDidMount() { + const { fetching, categoryLink, fetchChannel, resolveUris, claims } = this.props; + if (!fetching && categoryLink && (!claims || claims.length)) { + fetchChannel(categoryLink); + } + } + + uriForClaim = (claim) => { + const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = claim; + const uriParams = {}; + + // This is unfortunate + // https://github.com/lbryio/lbry/issues/1159 + const name = claimName || claimNameDownloaded; + uriParams.contentName = name; + uriParams.claimId = claimId; + const uri = buildURI(uriParams); + + return uri; + } + + render() { + const { categoryLink, fetching, obscureNsfw, claims, navigation } = this.props; + + if (!claims || !claims.length) { + return ( + + + + ); + } + + if (claims && claims.length > 0) { + return ( + + + {(claims.length > 1) && + ( + + ) + } + data={claims.slice(1, 4).map(claim => this.uriForClaim(claim))} + keyExtractor={(item, index) => item} + />} + + ); + } + + return null; + } +} + +export default SuggestedSubscriptionItem; diff --git a/app/src/component/suggestedSubscriptions/index.js b/app/src/component/suggestedSubscriptions/index.js new file mode 100644 index 0000000..1e46fdf --- /dev/null +++ b/app/src/component/suggestedSubscriptions/index.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; +import { selectSuggestedChannels, selectIsFetchingSuggested } from 'lbryinc'; +import SuggestedSubscriptions from './view'; + +const select = state => ({ + suggested: selectSuggestedChannels(state), + loading: selectIsFetchingSuggested(state), +}); + +export default connect( + select, + null +)(SuggestedSubscriptions); \ No newline at end of file diff --git a/app/src/component/suggestedSubscriptions/view.js b/app/src/component/suggestedSubscriptions/view.js new file mode 100644 index 0000000..cd2605d --- /dev/null +++ b/app/src/component/suggestedSubscriptions/view.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { ActivityIndicator, SectionList, Text, View } from 'react-native'; +import { normalizeURI } from 'lbry-redux'; +import SubscribeButton from 'component/subscribeButton'; +import SuggestedSubscriptionItem from 'component/suggestedSubscriptionItem'; +import Colors from 'styles/colors'; +import discoverStyle from 'styles/discover'; +import subscriptionsStyle from 'styles/subscriptions'; +import Link from 'component/link'; + +class SuggestedSubscriptions extends React.PureComponent { + render() { + const { suggested, loading, navigation } = this.props; + + if (loading) { + return ( + + + + ); + } + + return suggested ? ( + { console.log(item); return ( + + ); } + } + renderSectionHeader={ + ({section: {title}}) => { + const titleParts = title.split(';'); + const channelName = titleParts[0]; + const channelUri = normalizeURI(titleParts[1]); + return ( + + + + + ) + } + } + sections={suggested.map(({ uri, label }) => ({ title: (label + ';' + uri), data: [uri] }))} + keyExtractor={(item, index) => item} + /> + ) : null; + } +} + +export default SuggestedSubscriptions; \ No newline at end of file diff --git a/app/src/page/discover/view.js b/app/src/page/discover/view.js index 0eb65e1..a99277d 100644 --- a/app/src/page/discover/view.js +++ b/app/src/page/discover/view.js @@ -10,12 +10,12 @@ import { } from 'react-native'; import { normalizeURI, parseURI } from 'lbry-redux'; import moment from 'moment'; -import Colors from '../../styles/colors'; -import discoverStyle from '../../styles/discover'; -import FloatingWalletBalance from '../../component/floatingWalletBalance'; -import FileItem from '../../component/fileItem'; -import RewardSummary from '../../component/rewardSummary'; -import UriBar from '../../component/uriBar'; +import Colors from 'styles/colors'; +import discoverStyle from 'styles/discover'; +import FloatingWalletBalance from 'component/floatingWalletBalance'; +import FileItem from 'component/fileItem'; +import RewardSummary from 'component/rewardSummary'; +import UriBar from 'component/uriBar'; class DiscoverPage extends React.PureComponent { componentDidMount() { @@ -125,7 +125,9 @@ class DiscoverPage extends React.PureComponent { mediaStyle={discoverStyle.fileItemMedia} key={item} uri={normalizeURI(item)} - navigation={navigation} /> + navigation={navigation} + compactView={false} + showDetails={true} /> ) } renderSectionHeader={ diff --git a/app/src/page/subscriptions/index.js b/app/src/page/subscriptions/index.js index c96f3d6..9d75052 100644 --- a/app/src/page/subscriptions/index.js +++ b/app/src/page/subscriptions/index.js @@ -31,11 +31,8 @@ const select = state => ({ }); const perform = dispatch => ({ - doFetchMySubscriptions, - doSetViewMode, - doFetchRecommendedSubscriptions, - doCompleteFirstRun, - doShowSuggestedSubs, + doFetchMySubscriptions: () => dispatch(doFetchMySubscriptions()), + doFetchRecommendedSubscriptions: () => dispatch(doFetchRecommendedSubscriptions()), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)) }); diff --git a/app/src/page/subscriptions/view.js b/app/src/page/subscriptions/view.js index 4dd5bba..bde78c9 100644 --- a/app/src/page/subscriptions/view.js +++ b/app/src/page/subscriptions/view.js @@ -17,18 +17,20 @@ import discoverStyle from 'styles/discover'; import subscriptionsStyle from 'styles/subscriptions'; import FloatingWalletBalance from 'component/floatingWalletBalance'; import FileItem from 'component/fileItem'; +import SuggestedSubscriptions from 'component/suggestedSubscriptions'; import UriBar from 'component/uriBar'; class SubscriptionsPage extends React.PureComponent { - componentDidMount() { + componentWillMount() { const { doFetchMySubscriptions, doFetchRecommendedSubscriptions, pushDrawerStack, } = this.props; + pushDrawerStack(); doFetchMySubscriptions(); - //doFetchRecommendedSubscriptions(); + doFetchRecommendedSubscriptions(); } render() { @@ -77,10 +79,12 @@ class SubscriptionsPage extends React.PureComponent { } {!hasSubscriptions && - + - You are not subscribed to any channels. Feel free to discover new channels that you can subscribe to. + You are not subscribed to any channels at the moment. Here are some channels that we think you might enjoy. + {loadingSuggested && } + {!loadingSuggested && } } diff --git a/app/src/page/trending/view.js b/app/src/page/trending/view.js index 1bedc72..85b21e6 100644 --- a/app/src/page/trending/view.js +++ b/app/src/page/trending/view.js @@ -10,11 +10,11 @@ import { } from 'react-native'; import { normalizeURI } from 'lbry-redux'; import moment from 'moment'; -import FileItem from '../../component/fileItem'; -import discoverStyle from '../../styles/discover'; -import Colors from '../../styles/colors'; -import FloatingWalletBalance from '../../component/floatingWalletBalance'; -import UriBar from '../../component/uriBar'; +import FileItem from '/component/fileItem'; +import discoverStyle from 'styles/discover'; +import Colors from 'styles/colors'; +import FloatingWalletBalance from 'component/floatingWalletBalance'; +import UriBar from 'component/uriBar'; class TrendingPage extends React.PureComponent { componentDidMount() { @@ -44,7 +44,9 @@ class TrendingPage extends React.PureComponent { mediaStyle={discoverStyle.fileItemMedia} key={item} uri={normalizeURI(item)} - navigation={navigation} /> + navigation={navigation} + showDetails={true} + compactView={false} /> ) } data={trendingUris.map(uri => uri.url)} diff --git a/app/src/styles/discover.js b/app/src/styles/discover.js index 5d32987..4499dde 100644 --- a/app/src/styles/discover.js +++ b/app/src/styles/discover.js @@ -2,15 +2,15 @@ import { Dimensions, PixelRatio, StyleSheet } from 'react-native'; import Colors from './colors'; const screenDimension = Dimensions.get('window'); -const screenWidth = screenDimension.width; -const screenHeight = screenDimension.height; +export const screenWidth = screenDimension.width; +export const screenHeight = screenDimension.height; const screenWidthPixels = PixelRatio.getPixelSizeForLayoutSize(screenWidth); const screenHeightPixels = PixelRatio.getPixelSizeForLayoutSize(screenHeight); - // calculate thumbnail width and height based on device's aspect ratio -const horizontalMargin = 48; // left and right margins (24 + 24) -const verticalMargin = (screenWidthPixels > 720 && screenHeightPixels > 1920) ? 0 : ((screenWidthPixels <= 720) ? 20 : 16); -const mediaWidth = screenWidth - horizontalMargin; -const mediaHeight = ((screenWidth / screenHeight) * ((screenWidthPixels <= 720) ? screenWidth : mediaWidth)) - verticalMargin; +// calculate thumbnail width and height based on device's aspect ratio +export const horizontalMargin = 48; // left and right margins (24 + 24) +export const verticalMargin = (screenWidthPixels > 720 && screenHeightPixels > 1920) ? 0 : ((screenWidthPixels <= 720) ? 20 : 16); +export const mediaWidth = screenWidth - horizontalMargin; +export const mediaHeight = ((screenWidth / screenHeight) * ((screenWidthPixels <= 720) ? screenWidth : mediaWidth)) - verticalMargin; const discoverStyle = StyleSheet.create({ container: { diff --git a/app/src/styles/subscriptions.js b/app/src/styles/subscriptions.js index f6d2d85..cadd3af 100644 --- a/app/src/styles/subscriptions.js +++ b/app/src/styles/subscriptions.js @@ -1,4 +1,11 @@ import { StyleSheet } from 'react-native'; +import { + screenWidth, + horizontalMargin, + mediaWidth, + mediaHeight +} from 'styles/discover'; +import Colors from 'styles/colors'; const subscriptionsStyle = StyleSheet.create({ container: { @@ -19,14 +26,65 @@ const subscriptionsStyle = StyleSheet.create({ paddingTop: 24 }, infoText: { - textAlign: 'center', fontFamily: 'Inter-UI-Regular', fontSize: 16, + margin: 16 + }, + suggestedContainer: { + flex: 1, }, fileItem: { marginLeft: 24, marginRight: 24, - marginBottom: 24 + }, + compactItems: { + flex: 1, + marginTop: 6, + marginLeft: 20, + marginRight: 24, + marginBottom: 24, + height: 80, + }, + compactFileItem: { + width: (screenWidth - horizontalMargin - (6 * 3)) / 3, + marginLeft: 6, + height: '100%' + }, + compactFileItemMedia: { + width: (screenWidth - horizontalMargin) / 3, + height: '100%' + }, + fileItemMedia: { + width: mediaWidth, + height: mediaHeight, + alignItems: 'center', + justifyContent: 'center' + }, + fileItemName: { + fontFamily: 'Inter-UI-Bold', + marginTop: 8, + fontSize: 18 + }, + channelTitle: { + fontFamily: 'Inter-UI-SemiBold', + fontSize: 20, + marginLeft: 24, + marginTop: 16, + marginBottom: 16, + color: Colors.LbryGreen + }, + titleRow: { + flex: 1, + flexDirection: 'row', + justifyContent: 'space-between' + }, + subscribeButton: { + alignSelf: 'flex-start', + marginRight: 24, + marginTop: 8, + backgroundColor: Colors.White, + paddingLeft: 16, + paddingRight: 16, } });