diff --git a/app/package.json b/app/package.json
index 491c967d..555a398e 100644
--- a/app/package.json
+++ b/app/package.json
@@ -23,6 +23,7 @@
"react-native-image-zoom-viewer": "^2.2.5",
"react-native-password-strength-meter": "^0.0.2",
"react-native-phone-input": "lbryio/react-native-phone-input",
+ "react-native-super-grid": "^3.0.4",
"react-native-vector-icons": "^6.4.2",
"react-native-video": "lbryio/react-native-video#exoplayer-lbry-android",
"react-navigation": "^3.11.0",
diff --git a/app/src/component/AppNavigator.js b/app/src/component/AppNavigator.js
index 9ca1c955..aa644c56 100644
--- a/app/src/component/AppNavigator.js
+++ b/app/src/component/AppNavigator.js
@@ -5,6 +5,7 @@ import DownloadsPage from 'page/downloads';
import DrawerContent from 'component/drawerContent';
import FilePage from 'page/file';
import FirstRunScreen from 'page/firstRun';
+import PublishPage from 'page/publish';
import RewardsPage from 'page/rewards';
import TrendingPage from 'page/trending';
import SearchPage from 'page/search';
@@ -133,6 +134,9 @@ const drawer = createDrawerNavigator({
WalletStack: { screen: walletStack, navigationOptions: {
title: 'Wallet', drawerIcon: ({ tintColor }) =>
}},
+ Publish: { screen: PublishPage, navigationOptions: {
+ drawerIcon: ({ tintColor }) =>
+ }},
Rewards: { screen: RewardsPage, navigationOptions: {
drawerIcon: ({ tintColor }) =>
}},
diff --git a/app/src/component/gallery/index.js b/app/src/component/gallery/index.js
new file mode 100644
index 00000000..c942e248
--- /dev/null
+++ b/app/src/component/gallery/index.js
@@ -0,0 +1,4 @@
+import { connect } from 'react-redux';
+import Gallery from './view';
+
+export default connect()(Gallery);
diff --git a/app/src/component/gallery/view.js b/app/src/component/gallery/view.js
new file mode 100644
index 00000000..d45e756c
--- /dev/null
+++ b/app/src/component/gallery/view.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+class Gallery extends React.PureComponent {
+ render() {
+
+ }
+}
+
+export default Gallery;
diff --git a/app/src/constants.js b/app/src/constants.js
index a48197e7..ccd0584f 100644
--- a/app/src/constants.js
+++ b/app/src/constants.js
@@ -48,6 +48,7 @@ const Constants = {
DRAWER_ROUTE_TRENDING: "Trending",
DRAWER_ROUTE_SUBSCRIPTIONS: "Subscriptions",
DRAWER_ROUTE_MY_LBRY: "Downloads",
+ DRAWER_ROUTE_PUBLISH: "Publish",
DRAWER_ROUTE_REWARDS: "Rewards",
DRAWER_ROUTE_WALLET: "Wallet",
DRAWER_ROUTE_SETTINGS: "Settings",
diff --git a/app/src/page/publish/index.js b/app/src/page/publish/index.js
new file mode 100644
index 00000000..5b5ff94c
--- /dev/null
+++ b/app/src/page/publish/index.js
@@ -0,0 +1,13 @@
+import { connect } from 'react-redux';
+import { doToast } from 'lbry-redux';
+import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
+import Constants from 'constants';
+import PublishPage from './view';
+
+const perform = dispatch => ({
+ notify: data => dispatch(doToast(data)),
+ pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH)),
+ setPlayerVisible: () => dispatch(doSetPlayerVisible(false))
+});
+
+export default connect(null, perform)(PublishPage);
\ No newline at end of file
diff --git a/app/src/page/publish/view.js b/app/src/page/publish/view.js
new file mode 100644
index 00000000..ce6eb0c9
--- /dev/null
+++ b/app/src/page/publish/view.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import { NativeModules, Text, View } from 'react-native';
+import publishStyle from 'styles/reward';
+
+class PublishPage 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 { pushDrawerStack, setPlayerVisible } = this.props;
+
+ pushDrawerStack();
+ setPlayerVisible();
+ NativeModules.Gallery.getVideos().then(videos => {
+ console.log('videos retrieved.');
+ });
+ }
+
+ componentDidMount() {
+ this.onComponentFocused();
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const { currentRoute } = nextProps;
+ const { currentRoute: prevRoute } = this.props;
+
+ if (Constants.DRAWER_ROUTE_REWARDS === currentRoute && currentRoute !== prevRoute) {
+ this.onComponentFocused();
+ }
+ }
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default PublishPage;
diff --git a/app/src/styles/publish.js b/app/src/styles/publish.js
new file mode 100644
index 00000000..eeb87737
--- /dev/null
+++ b/app/src/styles/publish.js
@@ -0,0 +1,11 @@
+import { StyleSheet } from 'react-native';
+import Colors from './colors';
+
+const publishStyle = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.PageBackground
+ }
+});
+
+export default publishStyle;
diff --git a/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java b/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java
new file mode 100644
index 00000000..b3eb24bf
--- /dev/null
+++ b/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java
@@ -0,0 +1,146 @@
+package io.lbry.browser.reactmodules;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.MediaStore;
+import android.os.Bundle;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class GalleryModule extends ReactContextBaseJavaModule {
+ private Context context;
+
+ public GalleryModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ this.context = reactContext;
+ }
+
+ @Override
+ public String getName() {
+ return "Gallery";
+ }
+
+ @ReactMethod
+ public void getVideos(Promise promise) {
+ WritableArray items = Arguments.createArray();
+ List videos = loadVideos();
+ for (int i = 0; i < videos.size(); i++) {
+ items.pushMap(videos.get(i).toMap());
+ }
+
+ promise.resolve(items);
+ }
+
+ private List loadVideos() {
+ String[] projection = {
+ MediaStore.MediaColumns._ID,
+ MediaStore.MediaColumns.DATA,
+ MediaStore.MediaColumns.DISPLAY_NAME,
+ MediaStore.MediaColumns.MIME_TYPE,
+ MediaStore.Video.Media.DURATION
+ };
+
+ List items = new ArrayList();
+ Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
+ while (cursor.moveToNext()) {
+ int idColumn = cursor.getColumnIndex(MediaStore.MediaColumns._ID);
+ int nameColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
+ int typeColumn = cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE);
+ int pathColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
+ int durationColumn = cursor.getColumnIndex(MediaStore.Video.Media.DURATION);
+
+ GalleryItem item = new GalleryItem();
+ item.setId(cursor.getString(idColumn));
+ item.setName(cursor.getString(nameColumn));
+ item.setType(cursor.getString(typeColumn));
+ item.setFilePath(cursor.getString(pathColumn));
+ items.add(item);
+ }
+
+ return items;
+ }
+
+
+ private static class GalleryItem {
+ private String id;
+
+ private int duration;
+
+ private String filePath;
+
+ private String name;
+
+ private String thumbnailUri;
+
+ private String type;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public void setDuration(int duration) {
+ this.duration = duration;
+ }
+
+ public String getFilePath() {
+ return filePath;
+ }
+
+ public void setFilePath(String filePath) {
+ this.filePath = filePath;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getThumbnailUri() {
+ return thumbnailUri;
+ }
+
+ public void setThumnbailUri(String thumbnailUri) {
+ this.thumbnailUri = thumbnailUri;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public WritableMap toMap() {
+ WritableMap map = Arguments.createMap();
+ map.putString("id", id);
+ map.putString("name", name);
+ map.putString("filePath", filePath);
+ map.putString("type", type);
+ map.putString("thumbnailUri", thumbnailUri);
+ map.putInt("duration", duration);
+
+ return map;
+ }
+ }
+}
diff --git a/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java b/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java
index e6191344..6b535bae 100644
--- a/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java
+++ b/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java
@@ -9,6 +9,7 @@ import io.lbry.browser.reactmodules.BackgroundMediaModule;
import io.lbry.browser.reactmodules.DaemonServiceControlModule;
import io.lbry.browser.reactmodules.FirstRunModule;
import io.lbry.browser.reactmodules.FirebaseModule;
+import io.lbry.browser.reactmodules.GalleryModule;
import io.lbry.browser.reactmodules.ScreenOrientationModule;
import io.lbry.browser.reactmodules.VersionInfoModule;
import io.lbry.browser.reactmodules.UtilityModule;;
@@ -31,6 +32,7 @@ public class LbryReactPackage implements ReactPackage {
modules.add(new DaemonServiceControlModule(reactContext));
modules.add(new FirstRunModule(reactContext));
modules.add(new FirebaseModule(reactContext));
+ modules.add(new GalleryModule(reactContext));
modules.add(new ScreenOrientationModule(reactContext));
modules.add(new UtilityModule(reactContext));
modules.add(new VersionInfoModule(reactContext));