From bc7d546dd980ca151b6b864d7ed9bc932f8eb7a4 Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Fri, 26 Jul 2019 17:12:28 +0100
Subject: [PATCH 1/2] add publishes page

---
 src/component/AppNavigator.js      |  7 +++
 src/component/fileListItem/view.js |  3 +-
 src/constants.js                   |  3 ++
 src/page/publish/view.js           | 22 ++++----
 src/page/publishes/index.js        | 21 ++++++++
 src/page/publishes/view.js         | 80 ++++++++++++++++++++++++++++++
 src/styles/publish.js              | 43 ++++++++++++++++
 7 files changed, 167 insertions(+), 12 deletions(-)
 create mode 100644 src/page/publishes/index.js
 create mode 100644 src/page/publishes/view.js

diff --git a/src/component/AppNavigator.js b/src/component/AppNavigator.js
index 71cf69a..4db09a6 100644
--- a/src/component/AppNavigator.js
+++ b/src/component/AppNavigator.js
@@ -6,6 +6,7 @@ import DrawerContent from 'component/drawerContent';
 import FilePage from 'page/file';
 import FirstRunScreen from 'page/firstRun';
 import PublishPage from 'page/publish';
+import PublishesPage from 'page/publishes';
 import RewardsPage from 'page/rewards';
 import TagPage from 'page/tag';
 import TrendingPage from 'page/trending';
@@ -162,6 +163,12 @@ const drawer = createDrawerNavigator(
         drawerIcon: ({ tintColor }) => <Icon name="upload" size={20} style={{ color: tintColor }} />,
       },
     },
+    Publishes: {
+      screen: PublishesPage,
+      navigationOptions: {
+        drawerIcon: ({ tintColor }) => <Icon name="cloud-upload-alt" size={20} style={{ color: tintColor }} />,
+      },
+    },
     Rewards: {
       screen: RewardsPage,
       navigationOptions: {
diff --git a/src/component/fileListItem/view.js b/src/component/fileListItem/view.js
index fa24157..8301581 100644
--- a/src/component/fileListItem/view.js
+++ b/src/component/fileListItem/view.js
@@ -58,6 +58,7 @@ class FileListItem extends React.PureComponent {
       onPress,
       navigation,
       thumbnail,
+      hideChannel,
       title,
     } = this.props;
 
@@ -115,7 +116,7 @@ class FileListItem extends React.PureComponent {
                 {this.formatTitle(title) || this.formatTitle(name)}
               </Text>
             )}
-            {channel && (
+            {channel && !hideChannel && (
               <Link
                 style={fileListStyle.publisher}
                 text={channel}
diff --git a/src/constants.js b/src/constants.js
index 5bb40f2..a1b0e55 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -60,6 +60,7 @@ const Constants = {
   DRAWER_ROUTE_SUBSCRIPTIONS: 'Subscriptions',
   DRAWER_ROUTE_MY_LBRY: 'Downloads',
   DRAWER_ROUTE_PUBLISH: 'Publish',
+  DRAWER_ROUTE_PUBLISHES: 'Publishes',
   DRAWER_ROUTE_REWARDS: 'Rewards',
   DRAWER_ROUTE_WALLET: 'Wallet',
   DRAWER_ROUTE_SETTINGS: 'Settings',
@@ -113,6 +114,8 @@ export const DrawerRoutes = [
   Constants.DRAWER_ROUTE_MY_LBRY,
   Constants.DRAWER_ROUTE_REWARDS,
   Constants.DRAWER_ROUTE_WALLET,
+  Constants.DRAWER_ROUTE_PUBLISH,
+  Constants.DRAWER_ROUTE_PUBLISHES,
   Constants.DRAWER_ROUTE_SETTINGS,
   Constants.DRAWER_ROUTE_ABOUT,
   Constants.DRAWER_ROUTE_SEARCH,
diff --git a/src/page/publish/view.js b/src/page/publish/view.js
index 6b5fa9e..3c94144 100644
--- a/src/page/publish/view.js
+++ b/src/page/publish/view.js
@@ -123,6 +123,17 @@ class PublishPage extends React.PureComponent {
     }
   }
 
+  onComponentFocused = () => {
+    const { pushDrawerStack, setPlayerVisible } = this.props;
+
+    pushDrawerStack();
+    setPlayerVisible();
+
+    NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera }));
+    NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath }));
+    NativeModules.Gallery.getVideos().then(videos => this.setState({ videos }));
+  };
+
   getNewUri(name, channel) {
     const { resolveUri } = this.props;
     // If they are midway through a channel creation, treat it as anonymous until it completes
@@ -212,17 +223,6 @@ class PublishPage extends React.PureComponent {
     this.setState({ publishStarted: true }, () => publish(publishParams));
   };
 
-  onComponentFocused = () => {
-    const { pushDrawerStack, setPlayerVisible } = this.props;
-
-    pushDrawerStack();
-    setPlayerVisible();
-
-    NativeModules.Gallery.canUseCamera().then(canUseCamera => this.setState({ canUseCamera }));
-    NativeModules.Gallery.getThumbnailPath().then(thumbnailPath => this.setState({ thumbnailPath }));
-    NativeModules.Gallery.getVideos().then(videos => this.setState({ videos }));
-  };
-
   componentDidMount() {
     this.onComponentFocused();
   }
diff --git a/src/page/publishes/index.js b/src/page/publishes/index.js
new file mode 100644
index 0000000..3989253
--- /dev/null
+++ b/src/page/publishes/index.js
@@ -0,0 +1,21 @@
+import { connect } from 'react-redux';
+import { doCheckPendingPublishes, selectMyClaimUrisWithoutChannels, selectIsFetchingClaimListMine } from 'lbry-redux';
+import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
+import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
+import PublishesPage from './view';
+
+const select = state => ({
+  uris: selectMyClaimUrisWithoutChannels(state),
+  fetching: selectIsFetchingClaimListMine(state),
+});
+
+const perform = dispatch => ({
+  checkPendingPublishes: () => dispatch(doCheckPendingPublishes()),
+  pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_PUBLISHES)),
+  setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
+});
+
+export default connect(
+  select,
+  perform
+)(PublishesPage);
diff --git a/src/page/publishes/view.js b/src/page/publishes/view.js
new file mode 100644
index 0000000..3a09d06
--- /dev/null
+++ b/src/page/publishes/view.js
@@ -0,0 +1,80 @@
+import React from 'react';
+import { ActivityIndicator, FlatList, Text, TouchableOpacity, View } from 'react-native';
+import Button from 'component/button';
+import Colors from 'styles/colors';
+import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
+import FileListItem from 'component/fileListItem';
+import FloatingWalletBalance from 'component/floatingWalletBalance';
+import UriBar from 'component/uriBar';
+import publishStyle from 'styles/publish';
+import { __ } from 'utils/helper';
+
+class PublishesPage extends React.PureComponent {
+  didFocusListener;
+
+  componentWillMount() {
+    const { navigation } = this.props;
+    this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
+  }
+
+  componentWillUnmount() {
+    if (this.didFocusListener) {
+      this.didFocusListener.remove();
+    }
+  }
+
+  onComponentFocused = () => {
+    const { checkPendingPublishes, pushDrawerStack, setPlayerVisible } = this.props;
+
+    pushDrawerStack();
+    setPlayerVisible();
+    checkPendingPublishes();
+  };
+
+  render() {
+    const { fetching, navigation, uris } = this.props;
+
+    return (
+      <View style={publishStyle.container}>
+        <UriBar navigation={navigation} />
+        {fetching && (
+          <View style={publishStyle.centered}>
+            <ActivityIndicator size={'small'} color={Colors.LbryGreen} />
+          </View>
+        )}
+
+        {!fetching && (!uris || uris.length === 0) && (
+          <View style={publishStyle.noPublishes}>
+            <Text style={publishStyle.noPublishText}>
+              {__('It looks like you have not published anything to LBRY yet.')}
+            </Text>
+            <Button
+              style={publishStyle.publishNowButton}
+              text={__('Publish something new')}
+              onPress={() => navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH })}
+            />
+          </View>
+        )}
+
+        {uris && uris.length > 0 && (
+          <FlatList
+            style={publishStyle.publishesList}
+            contentContainerStyle={publishStyle.publishesScrollPadding}
+            initialNumToRender={8}
+            maxToRenderPerBatch={24}
+            removeClippedSubviews
+            renderItem={({ item }) => (
+              <FileListItem hideChannel key={item} uri={item} style={publishStyle.listItem} navigation={navigation} />
+            )}
+            data={uris}
+            keyExtractor={(item, index) => item}
+          />
+        )}
+
+        <FloatingWalletBalance navigation={navigation} />
+      </View>
+    );
+  }
+}
+
+export default PublishesPage;
diff --git a/src/styles/publish.js b/src/styles/publish.js
index f324d4c..b2db23d 100644
--- a/src/styles/publish.js
+++ b/src/styles/publish.js
@@ -326,6 +326,49 @@ const publishStyle = StyleSheet.create({
     fontSize: 14,
     marginLeft: 8,
   },
+  centered: {
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    top: 60,
+    bottom: 0,
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  noPublishes: {
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    top: 60,
+    bottom: 0,
+    alignItems: 'center',
+    justifyContent: 'center',
+    padding: 16,
+  },
+  noPublishText: {
+    fontFamily: 'Inter-UI-Regular',
+    fontSize: 16,
+  },
+  publishNowButton: {
+    alignSelf: 'center',
+    backgroundColor: Colors.LbryGreen,
+    marginTop: 16,
+  },
+  publishesList: {
+    flex: 1,
+    marginTop: 60,
+  },
+  publishesScrollPadding: {
+    paddingBottom: 16,
+  },
+  listItem: {
+    flex: 1,
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    marginTop: 8,
+    marginLeft: 8,
+    marginRight: 8,
+  },
 });
 
 export default publishStyle;
-- 
2.47.2


From 7a7530a970afd907b4f21768a674cd8ea0313f69 Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Mon, 29 Jul 2019 17:29:11 +0100
Subject: [PATCH 2/2] final discovery fixes

---
 src/component/claimList/index.js  | 22 +++++---
 src/component/claimList/view.js   | 91 +++++++++++++++++++++++++------
 src/component/modalPicker/view.js |  2 +-
 src/constants.js                  | 26 +++++++++
 src/page/discover/view.js         |  5 +-
 src/page/tag/view.js              | 33 +++++++++--
 src/styles/discover.js            | 23 ++++++++
 src/styles/modalPicker.js         |  3 +-
 8 files changed, 171 insertions(+), 34 deletions(-)

diff --git a/src/component/claimList/index.js b/src/component/claimList/index.js
index 2ab44d1..a621546 100644
--- a/src/component/claimList/index.js
+++ b/src/component/claimList/index.js
@@ -23,14 +23,22 @@ const select = (state, props) => {
 
 const perform = dispatch => ({
   claimSearch: options => dispatch(doClaimSearch(Constants.DEFAULT_PAGE_SIZE, options)),
-  searchByTags: (tags, orderBy = Constants.DEFAULT_ORDER_BY, page = 1) =>
+  searchByTags: (tags, orderBy = Constants.DEFAULT_ORDER_BY, page = 1, additionalOptions = {}) =>
     dispatch(
-      doClaimSearchByTags(tags, Constants.DEFAULT_PAGE_SIZE, {
-        no_totals: true,
-        order_by: orderBy,
-        page,
-        not_tags: MATURE_TAGS,
-      })
+      doClaimSearchByTags(
+        tags,
+        Constants.DEFAULT_PAGE_SIZE,
+        Object.assign(
+          {},
+          {
+            no_totals: true,
+            order_by: orderBy,
+            page,
+            not_tags: MATURE_TAGS,
+          },
+          additionalOptions
+        )
+      )
     ),
 });
 
diff --git a/src/component/claimList/view.js b/src/component/claimList/view.js
index 54f6246..33c10ce 100644
--- a/src/component/claimList/view.js
+++ b/src/component/claimList/view.js
@@ -1,14 +1,16 @@
 import React from 'react';
 import NavigationActions from 'react-navigation';
-import { ActivityIndicator, FlatList, Text, View } from 'react-native';
+import { ActivityIndicator, FlatList, Text, TouchableOpacity, View } from 'react-native';
 import { MATURE_TAGS, normalizeURI } 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 = 10;
 const softLimit = 500;
@@ -30,6 +32,7 @@ class ClaimList extends React.PureComponent {
       orderBy = Constants.DEFAULT_ORDER_BY,
       searchByTags,
       tags,
+      time,
     } = this.props;
     if (channelIds || trendingForAll) {
       const options = {
@@ -47,7 +50,11 @@ class ClaimList extends React.PureComponent {
 
       claimSearch(options);
     } else if (tags && tags.length > 0) {
-      searchByTags(tags, orderBy, this.state.currentPgae);
+      const additionalOptions = {};
+      if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
+        additionalOptions.release_time = this.getReleaseTimeOption(time);
+      }
+      searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
     }
   }
 
@@ -59,12 +66,14 @@ class ClaimList extends React.PureComponent {
       tags: prevTags,
       channelIds: prevChannelIds,
       trendingForAll: prevTrendingForAll,
+      time: prevTime,
     } = this.props;
-    const { orderBy, tags, channelIds, trendingForAll } = nextProps;
+    const { orderBy, tags, channelIds, trendingForAll, time } = nextProps;
     if (
       !_.isEqual(orderBy, prevOrderBy) ||
       !_.isEqual(tags, prevTags) ||
       !_.isEqual(channelIds, prevChannelIds) ||
+      time !== prevTime ||
       trendingForAll !== prevTrendingForAll
     ) {
       // reset to page 1 because the order, tags or channelIds changed
@@ -90,15 +99,27 @@ class ClaimList extends React.PureComponent {
           claimSearch(options);
         } else if (tags && tags.length > 0) {
           this.setState({ subscriptionsView: false, trendingForAllView: false });
-          searchByTags(tags, orderBy, this.state.currentPage);
+          const additionalOptions = {};
+          if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
+            additionalOptions.release_time = this.getReleaseTimeOption(time);
+          }
+          searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
         }
       });
     }
   }
 
+  getReleaseTimeOption = time => {
+    return `>${Math.floor(
+      moment()
+        .subtract(1, time)
+        .unix()
+    )}`;
+  };
+
   handleVerticalEndReached = () => {
     // fetch more content
-    const { channelIds, claimSearch, claimSearchUris, orderBy, searchByTags, tags, uris } = this.props;
+    const { channelIds, claimSearch, claimSearchUris, orderBy, searchByTags, tags, time, uris } = this.props;
     const { subscriptionsView, trendingForAllView } = this.state;
     if ((claimSearchUris && claimSearchUris.length >= softLimit) || (uris && uris.length >= softLimit)) {
       // don't fetch more than the specified limit to be displayed
@@ -119,17 +140,47 @@ class ClaimList extends React.PureComponent {
 
         claimSearch(options);
       } else {
-        searchByTags(tags, orderBy, this.state.currentPage);
+        const additionalOptions = {};
+        if (orderBy && orderBy[0] === Constants.ORDER_BY_EFFECTIVE_AMOUNT && Constants.TIME_ALL !== time) {
+          additionalOptions.release_time = this.getReleaseTimeOption(time);
+        }
+        searchByTags(tags, orderBy, this.state.currentPage, additionalOptions);
       }
     });
   };
 
+  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.FULL_ROUTE_NAME_TRENDING });
+    }
+  };
+
+  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>
+    );
+  };
+
   render() {
     const {
       ListHeaderComponent,
       loading,
       claimSearchLoading,
       claimSearchUris,
+      morePlaceholder,
       navigation,
       orientation = Constants.ORIENTATION_VERTICAL,
       style,
@@ -184,20 +235,24 @@ class ClaimList extends React.PureComponent {
           initialNumToRender={3}
           maxToRenderPerBatch={3}
           removeClippedSubviews
-          renderItem={({ item }) => (
-            <FileItem
-              style={discoverStyle.fileItem}
-              mediaStyle={discoverStyle.fileItemMedia}
-              key={item}
-              uri={normalizeURI(item)}
-              navigation={navigation}
-              showDetails
-              compactView={false}
-            />
-          )}
+          renderItem={({ item }) => {
+            return item === Constants.MORE_PLACEHOLDER ? (
+              this.renderMorePlaceholder()
+            ) : (
+              <FileItem
+                style={discoverStyle.fileItem}
+                mediaStyle={discoverStyle.fileItemMedia}
+                key={item}
+                uri={normalizeURI(item)}
+                navigation={navigation}
+                showDetails
+                compactView={false}
+              />
+            );
+          }}
           horizontal
           showsHorizontalScrollIndicator={false}
-          data={uris ? uris.slice(0, horizontalLimit) : []}
+          data={uris ? this.appendMorePlaceholder(uris.slice(0, horizontalLimit)) : []}
           keyExtractor={(item, index) => item}
         />
       );
diff --git a/src/component/modalPicker/view.js b/src/component/modalPicker/view.js
index 12dbd7e..b548f1a 100644
--- a/src/component/modalPicker/view.js
+++ b/src/component/modalPicker/view.js
@@ -45,7 +45,7 @@ export default class ModalPicker extends React.PureComponent {
                   style={modalPickerStyle.listItem}
                   onPress={() => onItemSelected(item)}
                 >
-                  <Icon style={modalPickerStyle.itemIcon} name={item.icon} size={16} />
+                  {item.icon && <Icon style={modalPickerStyle.itemIcon} name={item.icon} size={16} />}
                   <Text style={modalPickerStyle.itemLabel}>{item.label}</Text>
                   {selectedItem && selectedItem.name === item.name && (
                     <Icon style={modalPickerStyle.itemSelected} name={'check'} color={Colors.LbryGreen} size={16} />
diff --git a/src/constants.js b/src/constants.js
index 5bb40f2..1550e92 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -2,6 +2,12 @@ const SORT_BY_NEW = 'new';
 const SORT_BY_HOT = 'hot';
 const SORT_BY_TOP = 'top';
 
+const TIME_DAY = 'day';
+const TIME_WEEK = 'week';
+const TIME_MONTH = 'month';
+const TIME_YEAR = 'year';
+const TIME_ALL = 'all';
+
 const Constants = {
   FIRST_RUN_PAGE_WELCOME: 'welcome',
   FIRST_RUN_PAGE_EMAIL_COLLECT: 'email-collect',
@@ -89,18 +95,36 @@ const Constants = {
   SORT_BY_NEW,
   SORT_BY_TOP,
 
+  TIME_DAY,
+  TIME_WEEK,
+  TIME_MONTH,
+  TIME_YEAR,
+  TIME_ALL,
+
   CLAIM_SEARCH_SORT_BY_ITEMS: [
     { icon: 'fire-alt', name: SORT_BY_HOT, label: 'Hot content' },
     { icon: 'certificate', name: SORT_BY_NEW, label: 'New content' },
     { icon: 'chart-line', name: SORT_BY_TOP, label: 'Top content' },
   ],
 
+  CLAIM_SEARCH_TIME_ITEMS: [
+    { name: TIME_DAY, label: 'Past 24 hours' },
+    { name: TIME_WEEK, label: 'Past week' },
+    { name: TIME_MONTH, label: 'Past month' },
+    { name: TIME_YEAR, label: 'Past year' },
+    { name: TIME_ALL, label: 'All time' },
+  ],
+
   DEFAULT_ORDER_BY: ['trending_global', 'trending_mixed'],
 
+  ORDER_BY_EFFECTIVE_AMOUNT: 'effective_amount',
+
   DEFAULT_PAGE_SIZE: 10,
 
   ALL_PLACEHOLDER: '_all',
 
+  MORE_PLACEHOLDER: '_more',
+
   TRUE_STRING: 'true',
 };
 
@@ -111,6 +135,8 @@ export const DrawerRoutes = [
   Constants.DRAWER_ROUTE_TRENDING,
   Constants.DRAWER_ROUTE_SUBSCRIPTIONS,
   Constants.DRAWER_ROUTE_MY_LBRY,
+  Constants.DRAWER_ROUTE_TAG,
+  Constants.DRAWER_ROUTE_PUBLISH,
   Constants.DRAWER_ROUTE_REWARDS,
   Constants.DRAWER_ROUTE_WALLET,
   Constants.DRAWER_ROUTE_SETTINGS,
diff --git a/src/page/discover/view.js b/src/page/discover/view.js
index 4fcc569..875abc5 100644
--- a/src/page/discover/view.js
+++ b/src/page/discover/view.js
@@ -267,9 +267,10 @@ class DiscoverPage extends React.PureComponent {
           removeClippedSubviews
           renderItem={({ item, index, section }) => (
             <ClaimList
-              key={item.join(',')}
+              key={item.sort().join(',')}
               orderBy={item.length > 1 ? Constants.DEFAULT_ORDER_BY : orderBy}
               tags={item}
+              morePlaceholder
               navigation={navigation}
               orientation={Constants.ORIENTATION_HORIZONTAL}
             />
@@ -280,7 +281,7 @@ class DiscoverPage extends React.PureComponent {
                 {formatTagTitle(title)}
               </Text>
               <TouchableOpacity onPress={() => this.handleTagPress(title)}>
-                <Icon name={'ellipsis-v'} size={16} />
+                <Icon name={'angle-double-down'} size={16} />
               </TouchableOpacity>
             </View>
           )}
diff --git a/src/page/tag/view.js b/src/page/tag/view.js
index 8b685a6..843d4b9 100644
--- a/src/page/tag/view.js
+++ b/src/page/tag/view.js
@@ -19,8 +19,11 @@ class TagPage extends React.PureComponent {
   state = {
     tag: null,
     showSortPicker: false,
+    showTimePicker: false,
     orderBy: Constants.DEFAULT_ORDER_BY,
+    time: Constants.TIME_WEEK,
     currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[0],
+    currentTimeItem: Constants.CLAIM_SEARCH_TIME_ITEMS[1],
   };
 
   didFocusListener;
@@ -67,24 +70,34 @@ class TagPage extends React.PureComponent {
         break;
 
       case Constants.SORT_BY_TOP:
-        orderBy = ['effective_amount'];
+        orderBy = [Constants.ORDER_BY_EFFECTIVE_AMOUNT];
         break;
     }
 
     this.setState({ currentSortByItem: item, orderBy, showSortPicker: false });
   };
 
+  handleTimeItemSelected = item => {
+    this.setState({ time: item.name });
+  };
+
   render() {
     const { navigation } = this.props;
-    const { tag, currentSortByItem } = this.state;
+    const { tag, currentSortByItem, currentTimeItem, showSortPicker, showTimePicker } = this.state;
 
     return (
       <View style={discoverStyle.container}>
-        <UriBar navigation={navigation} belowOverlay={this.state.showSortPicker} />
+        <UriBar navigation={navigation} belowOverlay={showSortPicker || showTimePicker} />
         <ClaimList
           ListHeaderComponent={
             <View style={discoverStyle.tagTitleRow}>
               <Text style={discoverStyle.tagPageTitle}>{formatTagTitle(tag)}</Text>
+              {Constants.SORT_BY_TOP === currentSortByItem.name && (
+                <TouchableOpacity style={discoverStyle.tagTime} onPress={() => this.setState({ showTimePicker: true })}>
+                  <Text style={discoverStyle.tagSortText}>{currentTimeItem.label}</Text>
+                  <Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
+                </TouchableOpacity>
+              )}
               <TouchableOpacity style={discoverStyle.tagSortBy} onPress={() => this.setState({ showSortPicker: true })}>
                 <Text style={discoverStyle.tagSortText}>{currentSortByItem.label.split(' ')[0]}</Text>
                 <Icon style={discoverStyle.tagSortIcon} name={'sort-down'} size={14} />
@@ -93,12 +106,13 @@ class TagPage extends React.PureComponent {
           }
           style={discoverStyle.tagPageClaimList}
           orderBy={this.state.orderBy}
+          time={this.state.time}
           tags={[tag]}
           navigation={navigation}
           orientation={Constants.ORIENTATION_VERTICAL}
         />
-        {!this.state.showSortPicker && <FloatingWalletBalance navigation={navigation} />}
-        {this.state.showSortPicker && (
+        {!showSortPicker && !showTimePicker && <FloatingWalletBalance navigation={navigation} />}
+        {showSortPicker && (
           <ModalPicker
             title={__('Sort content by')}
             onOverlayPress={() => this.setState({ showSortPicker: false })}
@@ -107,6 +121,15 @@ class TagPage extends React.PureComponent {
             items={Constants.CLAIM_SEARCH_SORT_BY_ITEMS}
           />
         )}
+        {showTimePicker && (
+          <ModalPicker
+            title={__('Content from')}
+            onOverlayPress={() => this.setState({ showTimePicker: false })}
+            onItemSelected={this.handleTimeItemSelected}
+            selectedItem={this.state.currentTimeItem}
+            items={Constants.CLAIM_SEARCH_TIME_ITEMS}
+          />
+        )}
       </View>
     );
   }
diff --git a/src/styles/discover.js b/src/styles/discover.js
index d0ba91b..46d2301 100644
--- a/src/styles/discover.js
+++ b/src/styles/discover.js
@@ -85,6 +85,25 @@ const discoverStyle = StyleSheet.create({
     width: fileItemWidth,
     marginRight: 12,
   },
+  fileItemMore: {
+    alignSelf: 'flex-start',
+    backgroundColor: Colors.LbryGreen,
+    flexDirection: 'row',
+    width: fileItemWidth,
+    height: fileItemMediaHeight,
+    marginRight: 12,
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  moreText: {
+    fontFamily: 'Inter-UI-Regular',
+    color: Colors.White,
+    fontSize: 24,
+  },
+  moreIcon: {
+    marginLeft: 12,
+    marginBottom: -4,
+  },
   fileItemMedia: {
     width: fileItemMediaWidth,
     height: fileItemMediaHeight,
@@ -224,6 +243,10 @@ const discoverStyle = StyleSheet.create({
     alignItems: 'center',
     marginRight: 4,
   },
+  tagTime: {
+    flexDirection: 'row',
+    alignItems: 'center',
+  },
   tagSortText: {
     fontFamily: 'Inter-UI-Regular',
     fontSize: 14,
diff --git a/src/styles/modalPicker.js b/src/styles/modalPicker.js
index b412cba..41a615a 100644
--- a/src/styles/modalPicker.js
+++ b/src/styles/modalPicker.js
@@ -49,9 +49,10 @@ const modalPickerStyle = StyleSheet.create({
   },
   itemIcon: {
     marginLeft: 8,
-    marginRight: 12,
+    marginRight: 4,
   },
   itemLabel: {
+    marginLeft: 8,
     alignSelf: 'flex-start',
     fontFamily: 'Inter-UI-Regular',
     fontSize: 16,
-- 
2.47.2